From 109df1d0cbf07d1a495d12c321f8ba1911086665 Mon Sep 17 00:00:00 2001 From: Bertan Ari Date: Wed, 29 Apr 2026 09:54:26 -0700 Subject: [PATCH 1/3] chore: snapshot pending local changes --- .gitignore | 3 + .../commands/cli-release.md | 0 .../commands/commit.md | 0 .../commands/release.md | 0 .../commands/roo-resolve-conflicts.md | 0 .../commands/roo-translate.md | 0 .../guidance/roo-translator.md | 0 {.roo => .roo_backup_1776880534}/roomotes.yml | 0 .../rules-code/use-safeWriteJson.md | 0 .../rules-debug/cli.md | 0 .../1_extraction_workflow.xml | 0 .../2_verification_workflow.xml | 0 .../rules-docs-extractor/3_output_format.xml | 0 .../rules-issue-fixer/1_Workflow.xml | 0 .../rules-issue-fixer/2_best_practices.xml | 0 .../rules-issue-fixer/3_common_patterns.xml | 0 .../rules-issue-fixer/4_github_cli_usage.xml | 0 .../5_pull_request_workflow.xml | 0 .../6_testing_guidelines.xml | 0 .../7_communication_style.xml | 0 .../8_github_communication_guidelines.xml | 0 .../rules-issue-fixer/9_pr_template.xml | 0 .../rules-issue-investigator/1_workflow.xml | 0 .../2_best_practices.xml | 0 .../3_common_patterns.xml | 0 .../rules-issue-investigator/4_tool_usage.xml | 0 .../rules-issue-investigator/5_examples.xml | 0 .../6_communication.xml | 0 .../rules-issue-writer/1_workflow.xml | 0 .../rules-issue-writer/3_best_practices.xml | 0 .../4_common_mistakes_to_avoid.xml | 0 .../rules-issue-writer/5_examples.xml | 0 .../rules-merge-resolver/1_workflow.xml | 0 .../rules-merge-resolver/2_best_practices.xml | 0 .../rules-merge-resolver/3_tool_usage.xml | 0 .../4_complete_example.xml | 0 .../rules-merge-resolver/5_communication.xml | 0 .../rules-pr-fixer/1_workflow.xml | 0 .../rules-pr-fixer/2_best_practices.xml | 0 .../rules-pr-fixer/3_common_patterns.xml | 0 .../rules-pr-fixer/4_tool_usage.xml | 0 .../rules-pr-fixer/5_examples.xml | 0 .../rules-translate/001-general-rules.md | 0 .../rules-translate/instructions-de.md | 0 .../rules-translate/instructions-zh-cn.md | 0 .../rules-translate/instructions-zh-tw.md | 0 .../rules/rules.md | 0 .../skills/evals-context/SKILL.md | 0 .../skills/roo-conflict-resolution/SKILL.md | 0 .../skills/roo-translation/SKILL.md | 0 docs/analysis/mode-file-restrictions.md | 138 ++ docs/analysis/squad-vs-roo-comparison.md | 381 ++++ .../roo-to-copilot/00-executive-summary.md | 294 +++ docs/investigation/roo-to-copilot/00-plan.md | 146 ++ .../roo-to-copilot/10-roo-inventory.md | 226 +++ .../roo-to-copilot/20-roo-vault-inventory.md | 246 +++ .../roo-to-copilot/30-squad-inventory.md | 214 ++ .../40-copilot-chat-research.md | 1302 ++++++++++++ .../roo-to-copilot/50-copilot-cli-research.md | 1429 +++++++++++++ .../roo-to-copilot/60-gap-analysis.md | 266 +++ .../roo-to-copilot/70-migration-paths.md | 504 +++++ .../roo-to-copilot/80-migration-playbook.md | 1771 +++++++++++++++++ .../roo-to-copilot/90-decision-log.md | 716 +++++++ .../roo-to-copilot/99-open-questions.md | 127 ++ docs/investigation/roo-to-copilot/README.md | 83 + gh_output1.txt | 0 66 files changed, 7846 insertions(+) rename {.roo => .roo_backup_1776880534}/commands/cli-release.md (100%) rename {.roo => .roo_backup_1776880534}/commands/commit.md (100%) rename {.roo => .roo_backup_1776880534}/commands/release.md (100%) rename {.roo => .roo_backup_1776880534}/commands/roo-resolve-conflicts.md (100%) rename {.roo => .roo_backup_1776880534}/commands/roo-translate.md (100%) rename {.roo => .roo_backup_1776880534}/guidance/roo-translator.md (100%) rename {.roo => .roo_backup_1776880534}/roomotes.yml (100%) rename {.roo => .roo_backup_1776880534}/rules-code/use-safeWriteJson.md (100%) rename {.roo => .roo_backup_1776880534}/rules-debug/cli.md (100%) rename {.roo => .roo_backup_1776880534}/rules-docs-extractor/1_extraction_workflow.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-docs-extractor/2_verification_workflow.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-docs-extractor/3_output_format.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-fixer/1_Workflow.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-fixer/2_best_practices.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-fixer/3_common_patterns.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-fixer/4_github_cli_usage.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-fixer/5_pull_request_workflow.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-fixer/6_testing_guidelines.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-fixer/7_communication_style.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-fixer/8_github_communication_guidelines.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-fixer/9_pr_template.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-investigator/1_workflow.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-investigator/2_best_practices.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-investigator/3_common_patterns.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-investigator/4_tool_usage.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-investigator/5_examples.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-investigator/6_communication.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-writer/1_workflow.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-writer/3_best_practices.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-writer/4_common_mistakes_to_avoid.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-issue-writer/5_examples.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-merge-resolver/1_workflow.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-merge-resolver/2_best_practices.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-merge-resolver/3_tool_usage.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-merge-resolver/4_complete_example.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-merge-resolver/5_communication.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-pr-fixer/1_workflow.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-pr-fixer/2_best_practices.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-pr-fixer/3_common_patterns.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-pr-fixer/4_tool_usage.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-pr-fixer/5_examples.xml (100%) rename {.roo => .roo_backup_1776880534}/rules-translate/001-general-rules.md (100%) rename {.roo => .roo_backup_1776880534}/rules-translate/instructions-de.md (100%) rename {.roo => .roo_backup_1776880534}/rules-translate/instructions-zh-cn.md (100%) rename {.roo => .roo_backup_1776880534}/rules-translate/instructions-zh-tw.md (100%) rename {.roo => .roo_backup_1776880534}/rules/rules.md (100%) rename {.roo => .roo_backup_1776880534}/skills/evals-context/SKILL.md (100%) rename {.roo => .roo_backup_1776880534}/skills/roo-conflict-resolution/SKILL.md (100%) rename {.roo => .roo_backup_1776880534}/skills/roo-translation/SKILL.md (100%) create mode 100644 docs/analysis/mode-file-restrictions.md create mode 100644 docs/analysis/squad-vs-roo-comparison.md create mode 100644 docs/investigation/roo-to-copilot/00-executive-summary.md create mode 100644 docs/investigation/roo-to-copilot/00-plan.md create mode 100644 docs/investigation/roo-to-copilot/10-roo-inventory.md create mode 100644 docs/investigation/roo-to-copilot/20-roo-vault-inventory.md create mode 100644 docs/investigation/roo-to-copilot/30-squad-inventory.md create mode 100644 docs/investigation/roo-to-copilot/40-copilot-chat-research.md create mode 100644 docs/investigation/roo-to-copilot/50-copilot-cli-research.md create mode 100644 docs/investigation/roo-to-copilot/60-gap-analysis.md create mode 100644 docs/investigation/roo-to-copilot/70-migration-paths.md create mode 100644 docs/investigation/roo-to-copilot/80-migration-playbook.md create mode 100644 docs/investigation/roo-to-copilot/90-decision-log.md create mode 100644 docs/investigation/roo-to-copilot/99-open-questions.md create mode 100644 docs/investigation/roo-to-copilot/README.md create mode 100644 gh_output1.txt diff --git a/.gitignore b/.gitignore index 1dbcdc6a362..8381c043c62 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,6 @@ qdrant_storage/ plans/ roo-cli-*.tar.gz* +.roo +.roomodes +.clinerules diff --git a/.roo/commands/cli-release.md b/.roo_backup_1776880534/commands/cli-release.md similarity index 100% rename from .roo/commands/cli-release.md rename to .roo_backup_1776880534/commands/cli-release.md diff --git a/.roo/commands/commit.md b/.roo_backup_1776880534/commands/commit.md similarity index 100% rename from .roo/commands/commit.md rename to .roo_backup_1776880534/commands/commit.md diff --git a/.roo/commands/release.md b/.roo_backup_1776880534/commands/release.md similarity index 100% rename from .roo/commands/release.md rename to .roo_backup_1776880534/commands/release.md diff --git a/.roo/commands/roo-resolve-conflicts.md b/.roo_backup_1776880534/commands/roo-resolve-conflicts.md similarity index 100% rename from .roo/commands/roo-resolve-conflicts.md rename to .roo_backup_1776880534/commands/roo-resolve-conflicts.md diff --git a/.roo/commands/roo-translate.md b/.roo_backup_1776880534/commands/roo-translate.md similarity index 100% rename from .roo/commands/roo-translate.md rename to .roo_backup_1776880534/commands/roo-translate.md diff --git a/.roo/guidance/roo-translator.md b/.roo_backup_1776880534/guidance/roo-translator.md similarity index 100% rename from .roo/guidance/roo-translator.md rename to .roo_backup_1776880534/guidance/roo-translator.md diff --git a/.roo/roomotes.yml b/.roo_backup_1776880534/roomotes.yml similarity index 100% rename from .roo/roomotes.yml rename to .roo_backup_1776880534/roomotes.yml diff --git a/.roo/rules-code/use-safeWriteJson.md b/.roo_backup_1776880534/rules-code/use-safeWriteJson.md similarity index 100% rename from .roo/rules-code/use-safeWriteJson.md rename to .roo_backup_1776880534/rules-code/use-safeWriteJson.md diff --git a/.roo/rules-debug/cli.md b/.roo_backup_1776880534/rules-debug/cli.md similarity index 100% rename from .roo/rules-debug/cli.md rename to .roo_backup_1776880534/rules-debug/cli.md diff --git a/.roo/rules-docs-extractor/1_extraction_workflow.xml b/.roo_backup_1776880534/rules-docs-extractor/1_extraction_workflow.xml similarity index 100% rename from .roo/rules-docs-extractor/1_extraction_workflow.xml rename to .roo_backup_1776880534/rules-docs-extractor/1_extraction_workflow.xml diff --git a/.roo/rules-docs-extractor/2_verification_workflow.xml b/.roo_backup_1776880534/rules-docs-extractor/2_verification_workflow.xml similarity index 100% rename from .roo/rules-docs-extractor/2_verification_workflow.xml rename to .roo_backup_1776880534/rules-docs-extractor/2_verification_workflow.xml diff --git a/.roo/rules-docs-extractor/3_output_format.xml b/.roo_backup_1776880534/rules-docs-extractor/3_output_format.xml similarity index 100% rename from .roo/rules-docs-extractor/3_output_format.xml rename to .roo_backup_1776880534/rules-docs-extractor/3_output_format.xml diff --git a/.roo/rules-issue-fixer/1_Workflow.xml b/.roo_backup_1776880534/rules-issue-fixer/1_Workflow.xml similarity index 100% rename from .roo/rules-issue-fixer/1_Workflow.xml rename to .roo_backup_1776880534/rules-issue-fixer/1_Workflow.xml diff --git a/.roo/rules-issue-fixer/2_best_practices.xml b/.roo_backup_1776880534/rules-issue-fixer/2_best_practices.xml similarity index 100% rename from .roo/rules-issue-fixer/2_best_practices.xml rename to .roo_backup_1776880534/rules-issue-fixer/2_best_practices.xml diff --git a/.roo/rules-issue-fixer/3_common_patterns.xml b/.roo_backup_1776880534/rules-issue-fixer/3_common_patterns.xml similarity index 100% rename from .roo/rules-issue-fixer/3_common_patterns.xml rename to .roo_backup_1776880534/rules-issue-fixer/3_common_patterns.xml diff --git a/.roo/rules-issue-fixer/4_github_cli_usage.xml b/.roo_backup_1776880534/rules-issue-fixer/4_github_cli_usage.xml similarity index 100% rename from .roo/rules-issue-fixer/4_github_cli_usage.xml rename to .roo_backup_1776880534/rules-issue-fixer/4_github_cli_usage.xml diff --git a/.roo/rules-issue-fixer/5_pull_request_workflow.xml b/.roo_backup_1776880534/rules-issue-fixer/5_pull_request_workflow.xml similarity index 100% rename from .roo/rules-issue-fixer/5_pull_request_workflow.xml rename to .roo_backup_1776880534/rules-issue-fixer/5_pull_request_workflow.xml diff --git a/.roo/rules-issue-fixer/6_testing_guidelines.xml b/.roo_backup_1776880534/rules-issue-fixer/6_testing_guidelines.xml similarity index 100% rename from .roo/rules-issue-fixer/6_testing_guidelines.xml rename to .roo_backup_1776880534/rules-issue-fixer/6_testing_guidelines.xml diff --git a/.roo/rules-issue-fixer/7_communication_style.xml b/.roo_backup_1776880534/rules-issue-fixer/7_communication_style.xml similarity index 100% rename from .roo/rules-issue-fixer/7_communication_style.xml rename to .roo_backup_1776880534/rules-issue-fixer/7_communication_style.xml diff --git a/.roo/rules-issue-fixer/8_github_communication_guidelines.xml b/.roo_backup_1776880534/rules-issue-fixer/8_github_communication_guidelines.xml similarity index 100% rename from .roo/rules-issue-fixer/8_github_communication_guidelines.xml rename to .roo_backup_1776880534/rules-issue-fixer/8_github_communication_guidelines.xml diff --git a/.roo/rules-issue-fixer/9_pr_template.xml b/.roo_backup_1776880534/rules-issue-fixer/9_pr_template.xml similarity index 100% rename from .roo/rules-issue-fixer/9_pr_template.xml rename to .roo_backup_1776880534/rules-issue-fixer/9_pr_template.xml diff --git a/.roo/rules-issue-investigator/1_workflow.xml b/.roo_backup_1776880534/rules-issue-investigator/1_workflow.xml similarity index 100% rename from .roo/rules-issue-investigator/1_workflow.xml rename to .roo_backup_1776880534/rules-issue-investigator/1_workflow.xml diff --git a/.roo/rules-issue-investigator/2_best_practices.xml b/.roo_backup_1776880534/rules-issue-investigator/2_best_practices.xml similarity index 100% rename from .roo/rules-issue-investigator/2_best_practices.xml rename to .roo_backup_1776880534/rules-issue-investigator/2_best_practices.xml diff --git a/.roo/rules-issue-investigator/3_common_patterns.xml b/.roo_backup_1776880534/rules-issue-investigator/3_common_patterns.xml similarity index 100% rename from .roo/rules-issue-investigator/3_common_patterns.xml rename to .roo_backup_1776880534/rules-issue-investigator/3_common_patterns.xml diff --git a/.roo/rules-issue-investigator/4_tool_usage.xml b/.roo_backup_1776880534/rules-issue-investigator/4_tool_usage.xml similarity index 100% rename from .roo/rules-issue-investigator/4_tool_usage.xml rename to .roo_backup_1776880534/rules-issue-investigator/4_tool_usage.xml diff --git a/.roo/rules-issue-investigator/5_examples.xml b/.roo_backup_1776880534/rules-issue-investigator/5_examples.xml similarity index 100% rename from .roo/rules-issue-investigator/5_examples.xml rename to .roo_backup_1776880534/rules-issue-investigator/5_examples.xml diff --git a/.roo/rules-issue-investigator/6_communication.xml b/.roo_backup_1776880534/rules-issue-investigator/6_communication.xml similarity index 100% rename from .roo/rules-issue-investigator/6_communication.xml rename to .roo_backup_1776880534/rules-issue-investigator/6_communication.xml diff --git a/.roo/rules-issue-writer/1_workflow.xml b/.roo_backup_1776880534/rules-issue-writer/1_workflow.xml similarity index 100% rename from .roo/rules-issue-writer/1_workflow.xml rename to .roo_backup_1776880534/rules-issue-writer/1_workflow.xml diff --git a/.roo/rules-issue-writer/3_best_practices.xml b/.roo_backup_1776880534/rules-issue-writer/3_best_practices.xml similarity index 100% rename from .roo/rules-issue-writer/3_best_practices.xml rename to .roo_backup_1776880534/rules-issue-writer/3_best_practices.xml diff --git a/.roo/rules-issue-writer/4_common_mistakes_to_avoid.xml b/.roo_backup_1776880534/rules-issue-writer/4_common_mistakes_to_avoid.xml similarity index 100% rename from .roo/rules-issue-writer/4_common_mistakes_to_avoid.xml rename to .roo_backup_1776880534/rules-issue-writer/4_common_mistakes_to_avoid.xml diff --git a/.roo/rules-issue-writer/5_examples.xml b/.roo_backup_1776880534/rules-issue-writer/5_examples.xml similarity index 100% rename from .roo/rules-issue-writer/5_examples.xml rename to .roo_backup_1776880534/rules-issue-writer/5_examples.xml diff --git a/.roo/rules-merge-resolver/1_workflow.xml b/.roo_backup_1776880534/rules-merge-resolver/1_workflow.xml similarity index 100% rename from .roo/rules-merge-resolver/1_workflow.xml rename to .roo_backup_1776880534/rules-merge-resolver/1_workflow.xml diff --git a/.roo/rules-merge-resolver/2_best_practices.xml b/.roo_backup_1776880534/rules-merge-resolver/2_best_practices.xml similarity index 100% rename from .roo/rules-merge-resolver/2_best_practices.xml rename to .roo_backup_1776880534/rules-merge-resolver/2_best_practices.xml diff --git a/.roo/rules-merge-resolver/3_tool_usage.xml b/.roo_backup_1776880534/rules-merge-resolver/3_tool_usage.xml similarity index 100% rename from .roo/rules-merge-resolver/3_tool_usage.xml rename to .roo_backup_1776880534/rules-merge-resolver/3_tool_usage.xml diff --git a/.roo/rules-merge-resolver/4_complete_example.xml b/.roo_backup_1776880534/rules-merge-resolver/4_complete_example.xml similarity index 100% rename from .roo/rules-merge-resolver/4_complete_example.xml rename to .roo_backup_1776880534/rules-merge-resolver/4_complete_example.xml diff --git a/.roo/rules-merge-resolver/5_communication.xml b/.roo_backup_1776880534/rules-merge-resolver/5_communication.xml similarity index 100% rename from .roo/rules-merge-resolver/5_communication.xml rename to .roo_backup_1776880534/rules-merge-resolver/5_communication.xml diff --git a/.roo/rules-pr-fixer/1_workflow.xml b/.roo_backup_1776880534/rules-pr-fixer/1_workflow.xml similarity index 100% rename from .roo/rules-pr-fixer/1_workflow.xml rename to .roo_backup_1776880534/rules-pr-fixer/1_workflow.xml diff --git a/.roo/rules-pr-fixer/2_best_practices.xml b/.roo_backup_1776880534/rules-pr-fixer/2_best_practices.xml similarity index 100% rename from .roo/rules-pr-fixer/2_best_practices.xml rename to .roo_backup_1776880534/rules-pr-fixer/2_best_practices.xml diff --git a/.roo/rules-pr-fixer/3_common_patterns.xml b/.roo_backup_1776880534/rules-pr-fixer/3_common_patterns.xml similarity index 100% rename from .roo/rules-pr-fixer/3_common_patterns.xml rename to .roo_backup_1776880534/rules-pr-fixer/3_common_patterns.xml diff --git a/.roo/rules-pr-fixer/4_tool_usage.xml b/.roo_backup_1776880534/rules-pr-fixer/4_tool_usage.xml similarity index 100% rename from .roo/rules-pr-fixer/4_tool_usage.xml rename to .roo_backup_1776880534/rules-pr-fixer/4_tool_usage.xml diff --git a/.roo/rules-pr-fixer/5_examples.xml b/.roo_backup_1776880534/rules-pr-fixer/5_examples.xml similarity index 100% rename from .roo/rules-pr-fixer/5_examples.xml rename to .roo_backup_1776880534/rules-pr-fixer/5_examples.xml diff --git a/.roo/rules-translate/001-general-rules.md b/.roo_backup_1776880534/rules-translate/001-general-rules.md similarity index 100% rename from .roo/rules-translate/001-general-rules.md rename to .roo_backup_1776880534/rules-translate/001-general-rules.md diff --git a/.roo/rules-translate/instructions-de.md b/.roo_backup_1776880534/rules-translate/instructions-de.md similarity index 100% rename from .roo/rules-translate/instructions-de.md rename to .roo_backup_1776880534/rules-translate/instructions-de.md diff --git a/.roo/rules-translate/instructions-zh-cn.md b/.roo_backup_1776880534/rules-translate/instructions-zh-cn.md similarity index 100% rename from .roo/rules-translate/instructions-zh-cn.md rename to .roo_backup_1776880534/rules-translate/instructions-zh-cn.md diff --git a/.roo/rules-translate/instructions-zh-tw.md b/.roo_backup_1776880534/rules-translate/instructions-zh-tw.md similarity index 100% rename from .roo/rules-translate/instructions-zh-tw.md rename to .roo_backup_1776880534/rules-translate/instructions-zh-tw.md diff --git a/.roo/rules/rules.md b/.roo_backup_1776880534/rules/rules.md similarity index 100% rename from .roo/rules/rules.md rename to .roo_backup_1776880534/rules/rules.md diff --git a/.roo/skills/evals-context/SKILL.md b/.roo_backup_1776880534/skills/evals-context/SKILL.md similarity index 100% rename from .roo/skills/evals-context/SKILL.md rename to .roo_backup_1776880534/skills/evals-context/SKILL.md diff --git a/.roo/skills/roo-conflict-resolution/SKILL.md b/.roo_backup_1776880534/skills/roo-conflict-resolution/SKILL.md similarity index 100% rename from .roo/skills/roo-conflict-resolution/SKILL.md rename to .roo_backup_1776880534/skills/roo-conflict-resolution/SKILL.md diff --git a/.roo/skills/roo-translation/SKILL.md b/.roo_backup_1776880534/skills/roo-translation/SKILL.md similarity index 100% rename from .roo/skills/roo-translation/SKILL.md rename to .roo_backup_1776880534/skills/roo-translation/SKILL.md diff --git a/docs/analysis/mode-file-restrictions.md b/docs/analysis/mode-file-restrictions.md new file mode 100644 index 00000000000..d50b64886c0 --- /dev/null +++ b/docs/analysis/mode-file-restrictions.md @@ -0,0 +1,138 @@ +# How Roo limits the files a mode can read or edit + +Roo enforces per-mode file access through a layered system: **tool groups** decide *which tools* a mode can call, and an optional **`fileRegex`** on the `edit` group narrows *which files those edit tools may touch*. There is **no built-in regex restriction for read tools** — read access is gated only by group membership and by the workspace-wide `.rooignore` mechanism. + +## 1. Where restrictions are declared + +Each mode's capabilities live in its `groups` array. A group entry is either: + +- A bare group name: `"read"`, `"edit"`, `"command"`, `"mcp"`, `"browser"` +- Or a tuple `[groupName, options]` where `options` may include a `fileRegex` and `description` + +Schema in [packages/types/src/mode.ts](packages/types/src/mode.ts#L9-L39): + +```ts +export const groupOptionsSchema = z.object({ + fileRegex: z.string().optional().refine(/* validates it's a valid RegExp */), + description: z.string().optional(), +}) + +export const groupEntrySchema = z.union([ + toolGroupsSchema, + z.tuple([toolGroupsSchema, groupOptionsSchema]), +]) +``` + +The built-in **Architect** mode is the canonical example — it can read anything but only edit Markdown: + +```ts +groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }], "mcp"] +``` + +(See [packages/types/src/mode.ts](packages/types/src/mode.ts#L178).) + +Custom modes declared in `.roomodes` use the same shape and are validated by the same Zod schema. + +## 2. The two enforcement points + +### a) Tool availability — `isToolAllowedForMode` + +Lives in [src/core/tools/validateToolUse.ts](src/core/tools/validateToolUse.ts#L120). Called from `validateToolUse` before any tool dispatch and also when assembling the system prompt (so the LLM only sees tools it's allowed to use). + +Logic, in order: + +1. **Resolve aliases** (`search_and_replace`, `apply_diff`, `write_to_file`, `apply_patch`, etc. all map to the canonical `edit` tool). +2. **Tool-level disable** via `toolRequirements` short-circuits everything (used by `disabledTools`). +3. **Always-available tools** (`ask_followup_question`, `attempt_completion`, `new_task`, `switch_mode`, `update_todo_list`, etc.) bypass group checks. These cannot be restricted by mode configuration. +4. **Custom tools** registered through the experimental registry are allowed in any mode. +5. **Dynamic MCP tools** (`mcp__`) are allowed iff the mode has the `mcp` group. +6. **Walk the mode's `groups`**: for each entry, look up its tool list in `TOOL_GROUPS`. If the requested tool isn't in any allowed group, deny. +7. If the matching group has **no options**, allow. +8. If the matching group is `edit` *and* has a `fileRegex`, run the file-path check (next section). + +### b) File-path matching — only on `edit` + +When the matched group is `edit` with a `fileRegex`, the validator extracts the target path from the tool params: + +```ts +const filePath = toolParams?.path || toolParams?.file_path +const isEditOperation = EDIT_OPERATION_PARAMS.some((param) => toolParams?.[param]) +``` + +`EDIT_OPERATION_PARAMS` is the set of params that signal an actual write (not a streaming preamble): `diff`, `content`, `operations`, `search`, `replace`, `args`, `line`, `patch`, `old_string`, `new_string`. This avoids false positives while the LLM is still streaming a `` tag with no body yet. + +If the file fails the regex, the validator throws a `FileRestrictionError` (defined in [src/shared/modes.ts](src/shared/modes.ts#L135-L142)): + +``` +Tool 'write_to_file' in mode 'Architect' can only edit files matching pattern: \.md$ (Markdown files only). Got: src/foo.ts +``` + +The error is surfaced back to the LLM as a tool failure, so it can correct course (typically by switching modes via `switch_mode` or delegating via `new_task`). + +#### Special case: `apply_patch` + +Patch content can touch multiple files in one call. The validator parses the patch headers (`*** Add File:`, `*** Delete File:`, `*** Update File:`) via `extractFilePathsFromPatch` and validates **every** path against the regex. One bad file fails the whole patch. + +## 3. What this *doesn't* do + +- **No regex for `read`.** A `read` group entry currently ignores `fileRegex` — there's no per-mode read restriction in the validator. Read access is controlled purely by whether the mode has the `read` group at all. +- **No directory ACLs.** It's a single regex; if you need "src/ but not src/secrets/", encode it as a negative lookahead in the regex itself. +- **Doesn't override `.rooignore`.** Even if a mode's `fileRegex` allows a path, `.rooignore` (enforced by `RooIgnoreController`) still blocks it for both reads and writes. The two systems compose. +- **Doesn't override file protection.** Sensitive files (`.rooignore`, `.roo/*`, etc.) are also gated by the protected-files system, which can require explicit user approval regardless of mode. +- **Always-available tools cannot be restricted.** `attempt_completion`, `ask_followup_question`, `new_task`, `switch_mode`, `update_todo_list`, etc. work in every mode by design. + +## 4. End-to-end flow when the LLM tries to edit a file + +``` +LLM emits write_to_file { path: "src/foo.ts", content: "..." } + │ + ▼ +presentAssistantMessage (assistant-message/) + │ + ▼ +validateToolUse (core/tools/validateToolUse.ts) + │ + ├─ isValidToolName? → no → "Unknown tool" error + ├─ isToolAllowedForMode? + │ ├─ tool requirements / disabled? → deny + │ ├─ ALWAYS_AVAILABLE_TOOLS? → allow + │ ├─ walk mode.groups for the canonical tool + │ │ match found → has fileRegex? + │ │ yes → doesFileMatchRegex(path)? + │ │ no → throw FileRestrictionError + │ │ yes → allow + │ │ no → allow + │ └─ no group matched → deny + ▼ +EditFileTool / ApplyDiffTool / WriteToFileTool + ▼ +RooIgnoreController.validateAccess(path) ← second gate (.rooignore) + ▼ +Protected-files check (e.g., .roo/*) ← third gate (may require approval) + ▼ +DiffViewProvider / FS write +``` + +## 5. Practical patterns + +| Goal | Configuration | +| --- | --- | +| Mode that can only edit Markdown (docs writer) | `groups: ["read", ["edit", { fileRegex: "\\.md$", description: "Markdown files only" }]]` | +| Mode that can only touch tests | `groups: ["read", ["edit", { fileRegex: "(^|/)__tests__/|\\.spec\\.[tj]sx?$|\\.test\\.[tj]sx?$" }]]` | +| Mode confined to a folder | `groups: ["read", ["edit", { fileRegex: "^src/agent/" }]]` | +| Read-only review mode | `groups: ["read", "mcp"]` (omit `edit` entirely) | +| Pure planner (cannot read or edit) | `groups: []` — same approach Orchestrator uses | +| Allow edits everywhere except secrets | `groups: ["read", ["edit", { fileRegex: "^(?!.*secrets/).*$" }]]` | + +## 6. UI surface + +The Modes view ([webview-ui/src/components/modes/ModesView.tsx](webview-ui/src/components/modes/ModesView.tsx#L1174-L1220)) reads the same tuple structure to render badges like "Markdown files only" next to the `edit` group, and the mode editor lets users supply the regex + description directly. The Zod schema in `packages/types` validates input on save, so an invalid regex is rejected at the form layer. + +## 7. Key files + +- [packages/types/src/mode.ts](packages/types/src/mode.ts) — `groupOptionsSchema`, `groupEntrySchema`, built-in modes, `fileRegex` field. +- [src/core/tools/validateToolUse.ts](src/core/tools/validateToolUse.ts) — `isToolAllowedForMode`, `doesFileMatchRegex`, `extractFilePathsFromPatch`, alias resolution. +- [src/shared/modes.ts](src/shared/modes.ts#L135) — `FileRestrictionError`. +- [src/shared/tools.ts](src/shared/tools.ts) — `TOOL_GROUPS` (which tools belong to `read` / `edit` / `command` / `mcp` / `browser`), `ALWAYS_AVAILABLE_TOOLS`, `TOOL_ALIASES`. +- [src/shared/__tests__/modes.spec.ts](src/shared/__tests__/modes.spec.ts) — behavioral tests for `fileRegex` enforcement (good reference for edge cases). +- `RooIgnoreController` (under `src/core/ignore/`) — orthogonal `.rooignore` enforcement layered on top. diff --git a/docs/analysis/squad-vs-roo-comparison.md b/docs/analysis/squad-vs-roo-comparison.md new file mode 100644 index 00000000000..23ef5685f43 --- /dev/null +++ b/docs/analysis/squad-vs-roo-comparison.md @@ -0,0 +1,381 @@ +# Squad vs. Roo-Code — Comparative Analysis + +A side-by-side architectural and feature comparison of two AI agent systems sitting in adjacent corners of the developer-tooling space: + +- **Squad** (`@bradygaster/squad`) — a CLI + SDK that orchestrates multi-agent "teams" on top of GitHub Copilot. +- **Roo-Code** (`roo-cline`) — a VS Code extension descended from Cline that ships a fully self-contained AI coding agent with its own provider layer. + +All paths in this report are repo-relative. Squad paths are rooted at `c:/git/squad`; Roo-Code paths are rooted at `c:/git/Roo-Code`. + +--- + +## 1. Project Overview & Purpose + +### Squad + +Squad bills itself as **"human-led AI agent teams for any project"** and explicitly targets GitHub Copilot as its execution substrate. From [`README.md`](../../README.md:1) (Squad): + +> Squad gives you a human-directed AI development team through GitHub Copilot. … Each team member runs in its own context, reads only its own knowledge, and writes back what it learned so the work stays inspectable. + +It is distributed as two npm packages — [`@bradygaster/squad-sdk`](../../packages/squad-sdk/package.json:2) and [`@bradygaster/squad-cli`](../../packages/squad-cli/package.json:2) (both currently `0.9.1`, alpha) — installed globally and driven from the terminal (`squad init`, `squad triage`, `copilot --agent squad`). State for a team lives in a committed `.squad/` directory of markdown files (charters, history, decisions, routing). + +- **License:** MIT +- **Target audience:** developers already using GitHub Copilot who want a persistent, file-backed multi-agent layer on top of it +- **Distribution:** npm CLI + SDK; agents are markdown definitions living in the user's repo +- **Lineage:** original work by `@bradygaster`; not a fork of Roo or Cline + +### Roo-Code + +Roo-Code is a **VS Code extension** providing an autonomous AI coding agent. From [`src/package.json`](../src/package.json:2) it publishes as `roo-cline` (publisher `RooVeterinaryInc`, version `3.52.1`). The README and historical naming make clear it is a **fork/derivative of Cline** that has diverged substantially: deep settings UI, modes system, model marketplace, evals harness, cloud telemetry, etc. + +- **License:** see [`LICENSE`](../../LICENSE) (Apache 2.0-style, project specific) +- **Target audience:** VS Code users who want an in-IDE autonomous coding agent with broad provider choice +- **Distribution:** `.vsix` published to the VS Code Marketplace and OpenVSX; nightly variant via [`apps/vscode-nightly`](../../apps/vscode-nightly) +- **Lineage:** fork of Cline (the codebase still uses `roo-cline` and `cline` terminology in many places, e.g. [`src/__tests__/removeClineFromStack-delegation.spec.ts`](../../src/__tests__/removeClineFromStack-delegation.spec.ts:1)) + +The two projects are **not related by fork**. They occupy adjacent niches: Squad delegates execution to Copilot and focuses on team orchestration; Roo-Code owns its own model loop and focuses on a single in-IDE agent (with sub-agent "modes"). + +--- + +## 2. Repository Structure + +### Squad — npm-workspaces monorepo + +[`package.json`](../../package.json:7) declares `workspaces: ["packages/*"]` with two packages: + +``` +packages/ +├── squad-sdk/ → @bradygaster/squad-sdk (the runtime library) +└── squad-cli/ → @bradygaster/squad-cli (the binary) +``` + +Top-level layout (from `list_files c:/git/squad`): + +- [`packages/squad-sdk/src/`](../../packages/squad-sdk/src) — **the bulk of the codebase**: ~30 subsystems (agents, casting, coordinator, ralph, runtime, marketplace, sharing, platform, storage, streams, …) +- [`packages/squad-cli/src/`](../../packages/squad-cli/src) — `cli/`, `shell/`, `commands/`, plus a `remote-ui/` +- [`templates/`](../../templates) — markdown templates copied into a user's `.squad/` directory on `squad init` (charters, ceremonies, routing, ralph-triage, etc.) +- [`samples/`](../../samples) — eight sample projects +- [`docs/`](../../docs) — Astro-based documentation site (`astro.config.mjs`, `pagefind.yml`, Playwright tests) +- [`test/`](../../test) — flat directory with **~200 test files** (vitest) +- [`.changeset/`](../../.changeset) — independent versioning per package + +Tooling: TypeScript 5.7, ESLint 10, vitest 3, Playwright, markdownlint, cspell, esbuild for the CLI bundle (`cli.js`). Build pipeline is plain `tsc` per package plus a postbuild copy step. + +### Roo-Code — pnpm + Turbo monorepo + +The root [`package.json`](../package.json:2) uses `pnpm@10.8.1` and Turbo for task orchestration. [`pnpm-workspace.yaml`](../pnpm-workspace.yaml) declares multiple workspaces: + +- [`src/`](../src) — the **VS Code extension itself** (`roo-cline`), with subsystems under [`src/core/`](../src/core) (assistant-message, tools, prompts, task, condense, checkpoints, mentions, message-queue, …), [`src/api/providers/`](../src/api/providers), [`src/services/`](../src/services), [`src/integrations/`](../src/integrations), [`src/i18n/`](../src/i18n) +- [`webview-ui/`](../webview-ui) — React + Vite app rendered in the extension's webview +- [`apps/`](../apps) — peripheral apps: [`apps/cli`](../apps/cli), [`apps/vscode-e2e`](../apps/vscode-e2e), [`apps/vscode-nightly`](../apps/vscode-nightly), [`apps/web-evals`](../apps/web-evals), [`apps/web-roo-code`](../apps/web-roo-code) +- [`packages/`](../packages) — shared libs: [`packages/types`](../packages/types), [`packages/cloud`](../packages/cloud), [`packages/telemetry`](../packages/telemetry), [`packages/ipc`](../packages/ipc), [`packages/evals`](../packages/evals), [`packages/build`](../packages/build), [`packages/vscode-shim`](../packages/vscode-shim), config-* packages +- [`locales/`](../locales) and [`src/i18n/`](../src/i18n) — 14+ localized README/CONTRIBUTING and runtime translation files +- [`.changeset/`](../.changeset) — also uses changesets + +Build/packaging tooling: Turbo + esbuild ([`src/esbuild.mjs`](../src/esbuild.mjs)), `@vscode/vsce`, `ovsx`. Bundling produces a `.vsix` rather than an npm tarball. + +**Net:** Squad is a "two-package SDK + CLI" monorepo of moderate size. Roo-Code is a **much larger** product monorepo containing the extension, a webview SPA, multiple supporting apps, and a docker-based evals harness. + +--- + +## 3. Tech Stack & Dependencies + +| Dimension | Squad | Roo-Code | +|---|---|---| +| Languages | TypeScript (strict, ESM) | TypeScript (mix CJS/ESM, extension is CJS) | +| Node | `>=22.5.0` ([`package.json`](../../package.json:27)) | `20.19.2` (pinned, [`package.json`](../package.json:5)) | +| Package mgr | npm workspaces | pnpm + Turbo | +| Test | vitest 3, Playwright | vitest, Playwright (e2e), `@vscode/test-electron` | +| Build | `tsc` + esbuild bundle | esbuild + Turbo + `vsce`/`ovsx` | +| Lint | ESLint 10 + `tsc --noEmit` | ESLint 9 + Turbo `check-types` | +| Docs lint | markdownlint-cli2 + cspell | prettier + lint-staged | +| UI runtime | **Ink + React 19** (terminal UI, [`squad-cli/package.json`](../../packages/squad-cli/package.json:185)) | **React 18** in a VS Code webview (`webview-ui/`) | +| Core LLM dep | `@github/copilot-sdk` ^0.1.32 ([`squad-sdk/package.json`](../../packages/squad-sdk/package.json:235)) | ~30+ provider SDKs (see §4) | +| Telemetry | OpenTelemetry (optional deps for grpc exporters, traces, metrics) | Custom + PostHog via [`packages/telemetry`](../packages/telemetry) | +| Storage | Pluggable: fs / in-memory / sql.js ([`squad-sdk/src/storage/`](../../packages/squad-sdk/src/storage)) | VS Code globalState + workspace files; checkpoints via shadow git | + +The starkest dependency contrast: **Squad has essentially one model dependency** (`@github/copilot-sdk`) plus optional OpenTelemetry. **Roo-Code has direct integrations with ~30 model providers** (see [`src/api/providers/`](../src/api/providers)) — Anthropic, OpenAI, OpenAI-Codex, Bedrock, Vertex, Gemini, DeepSeek, Mistral, Moonshot, Fireworks, Groq, OpenRouter, Requesty, Unbound, Vercel AI Gateway, LM Studio, Ollama, LiteLLM, Baseten, SambaNova, Poe, Qwen-Code, MiniMax, xAI, Z.AI, VS Code LM API, plus a `roo` first-party gateway. + +--- + +## 4. Core Architecture + +### 4a. Host architecture & entry points + +- **Squad** is a **Node CLI** binary ([`packages/squad-cli/src/cli-entry.ts`](../../packages/squad-cli/src/cli-entry.ts)). Its primary "agent execution" path is to **shell out to the GitHub Copilot CLI** (`gh copilot` / `copilot --agent squad`) with a context file. There is no IDE host. An optional Ink-based interactive shell is shipped but marked deprecated in favor of the Copilot CLI. +- **Roo-Code** activates inside a VS Code extension host ([`src/extension.ts`](../src/extension.ts)) and renders its UI in a webview (`webview-ui/`). The extension owns its own task/agent execution loop entirely in-process. + +### 4b. Task / agent execution loop + +- **Squad** implements a **coordinator + fan-out** pattern, with explicit tier-based response selection: + - [`packages/squad-sdk/src/coordinator/coordinator.ts`](../../packages/squad-sdk/src/coordinator/coordinator.ts) — primary coordinator + - [`packages/squad-sdk/src/coordinator/fan-out.ts`](../../packages/squad-sdk/src/coordinator/fan-out.ts) — parallel agent dispatch + - [`packages/squad-sdk/src/coordinator/response-tiers.ts`](../../packages/squad-sdk/src/coordinator/response-tiers.ts) — model tiering + - Long-running automation lives under [`packages/squad-sdk/src/ralph/`](../../packages/squad-sdk/src/ralph) ("Ralph" = the watch/triage daemon with rate limiting, capabilities, polling) +- **Roo-Code** runs a single in-process agent loop centered on the `Task` (formerly `Cline`) class under [`src/core/task/`](../src/core/task), with a tightly woven set of subsystems for assistant-message parsing, message queueing, context management, condense (auto-summarization), checkpoints, and tool invocation. Sub-agents are spawned via the `new_task` tool and tracked in a stack ([`src/__tests__/nested-delegation-resume.spec.ts`](../src/__tests__/nested-delegation-resume.spec.ts)). + +### 4c. Provider / model abstraction + +- **Squad** does not abstract over multiple models in the Roo sense — it delegates to Copilot. Model selection is a **policy** ([`config/models.ts`](../../packages/squad-sdk/src/config/models.ts), [`agents/model-selector.ts`](../../packages/squad-sdk/src/agents/model-selector.ts)) about which Copilot-available model tier ("haiku-4.5", "sonnet-4", etc.) a given role/task should use. +- **Roo-Code** has a first-class provider abstraction in [`src/api/providers/`](../src/api/providers) with a [`base-provider.ts`](../src/api/providers/base-provider.ts) and [`base-openai-compatible-provider.ts`](../src/api/providers/base-openai-compatible-provider.ts), each concrete provider implementing model listing, streaming, function calling, and cost accounting. ~30 providers are shipped. + +### 4d. Prompt construction + +- **Squad** prompts are largely **markdown documents** authored by the user (per-agent `charter.md`, `history.md`, team `routing.md`, plus templates under [`templates/`](../../templates)). The runtime composes them via the charter compiler ([`agents/charter-compiler.ts`](../../packages/squad-sdk/src/agents/charter-compiler.ts)). +- **Roo-Code** has a **programmatic prompt system** under [`src/core/prompts/`](../src/core/prompts) — [`system.ts`](../src/core/prompts/system.ts) assembles the system prompt from per-mode templates, tool descriptions ([`tools/native-tools/`](../src/core/prompts/tools/native-tools) and the legacy XML tool descriptions), capability sections, and i18n strings. + +### 4e. Tool system + +- **Squad** exposes a `tools/` module ([`packages/squad-sdk/src/tools/index.ts`](../../packages/squad-sdk/src/tools/index.ts)) and a `hooks/` module for custom tool plumbing. Because actual execution happens through the Copilot agent runner, "tools" in Squad are largely SDK-side primitives: file-write guards, PII scrubbing, reviewer lockout (per [`README.md`](../../README.md:478)). +- **Roo-Code** has a **rich, dual-format tool surface** under [`src/core/tools/`](../src/core/tools) and [`src/core/prompts/tools/`](../src/core/prompts/tools) — read_file, apply_diff, write_to_file, execute_command, browser_action, search_files, list_files, codebase_search, new_task, switch_mode, ask_followup_question, attempt_completion, plus MCP tool/resource invocations. It supports both XML-style tool calls (legacy/Cline) and provider-native function calling (e.g. [`src/core/prompts/tools/native-tools/`](../src/core/prompts/tools/native-tools)). + +### 4f. MCP support + +- **Squad** has only lightweight MCP **configuration** awareness — see [`templates/mcp-config.md`](../../templates/mcp-config.md) and [`test/mcp-config.test.cjs`](../../test/mcp-config.test.cjs). MCP servers are passed *through* to Copilot via flags; Squad does not host the MCP client itself. +- **Roo-Code** is a **first-class MCP client host**. It manages MCP server lifecycle, exposes server tools/resources to the agent, surfaces a Settings UI for them, and supports per-mode allow-listing of servers (see [`docs/design/per-mode-mcp-settings.md`](../design/per-mode-mcp-settings.md), [`src/core/prompts/tools/native-tools/mcp_server.ts`](../../src/core/prompts/tools/native-tools/mcp_server.ts), [`packages/types/src/__tests__/mode-allowedMcpServers.spec.ts`](../../packages/types/src/__tests__/mode-allowedMcpServers.spec.ts), [`webview-ui/src/components/modes/McpServerRestriction.tsx`](../../webview-ui/src/components/modes/McpServerRestriction.tsx)). + +### 4g. Modes / personas / agents + +This is the most direct conceptual overlap, but the implementations differ. + +- **Squad agents** are **persistent, named team members** ("Edie", "McManus", "Keaton" — drawn from a casting registry in [`packages/squad-sdk/src/casting/`](../../packages/squad-sdk/src/casting)). Each has a `charter.md`, an evolving `history.md`, and a role from a catalog ([`roles/catalog.ts`](../../packages/squad-sdk/src/roles/catalog.ts)). Agents are intended to *learn* (write back to `history.md`) and persist across sessions in git. +- **Roo-Code modes** are **stateless personas** keyed by slug (`code`, `architect`, `ask`, `debug`, `orchestrator`, plus user customs). Defined in [`packages/types/src/mode.ts`](../../packages/types/src/mode.ts) and configured via [`.roomodes`](../../.roomodes) (per-project) and `custom_modes.yaml` (per-user). Each mode has tool restrictions, file regex restrictions, role definition, and (recently) `allowedMcpServers`. + +### 4h. State & persistence + +- **Squad** writes state into the **working tree's `.squad/`** (or, optionally, externalizes it via `squad externalize`). State backends include git-notes and orphan branches for the watch loop ([`packages/squad-sdk/src/state-backend.ts`](../../packages/squad-sdk/src/state-backend.ts)). Storage providers are pluggable: fs, in-memory, sql.js ([`packages/squad-sdk/src/storage/`](../../packages/squad-sdk/src/storage)). +- **Roo-Code** persists in VS Code `globalState`/`workspaceState` and on disk under the extension's storage, plus shadow-git **checkpoints** ([`src/core/checkpoints/`](../src/core/checkpoints)) for diff-style rollback inside a task. + +### 4i. Internationalization + +- **Squad** has a runtime i18n module ([`packages/squad-sdk/src/runtime/i18n.ts`](../../packages/squad-sdk/src/runtime/i18n.ts)) and Chinese README ([`README.zh.md`](../../README.zh.md)), but the project is largely English-only. +- **Roo-Code** ships a **deep i18n system**: 14+ locales for both extension strings ([`src/i18n/locales/`](../src/i18n)) and webview strings ([`webview-ui/src/i18n/locales/`](../webview-ui/src/i18n)), localized `package.nls.*.json`, and 14+ fully-translated `README.md` / `CONTRIBUTING.md` under [`locales/`](../locales). + +### 4j. Parallel agent execution ⚡ + +This is one of the most consequential architectural divergences and deserves its own section. **Squad treats parallelism as a first-class primitive at every layer; Roo-Code is sequential by deliberate design.** + +#### Squad — parallel by default + +| Layer | Squad implementation | File | +|---|---|---| +| **Routing** | Coordinator returns `parallel: true/false` per request and emits OTel spans for it | [`packages/squad-sdk/src/coordinator/index.ts`](../../packages/squad-sdk/src/coordinator/index.ts) | +| **Fan-out spawn** | Multi-agent dispatch via `Promise.allSettled` for max throughput | [`packages/squad-sdk/src/coordinator/fan-out.ts`](../../packages/squad-sdk/src/coordinator/fan-out.ts) | +| **Session pool** | Lifecycle manager for concurrent agent sessions with concurrency limits | [`packages/squad-sdk/src/client/session-pool.ts`](../../packages/squad-sdk/src/client/session-pool.ts) | +| **User syntax** | `@Agent1 @Agent2 message` triggers parallel dispatch from the interactive shell | [`packages/squad-cli/src/cli/shell/index.ts`](../../packages/squad-cli/src/cli/shell/index.ts) | +| **Wave dispatch** | `--wave-dispatch` flag for parallel sub-task execution *within* a single issue | [`packages/squad-cli/src/cli/commands/watch/capabilities/wave-dispatch.ts`](../../packages/squad-cli/src/cli/commands/watch/capabilities/wave-dispatch.ts) | +| **Fleet dispatch** | Batches read-heavy issues into one parallel `/fleet` Copilot session | [`packages/squad-cli/src/cli/commands/watch/capabilities/fleet-dispatch.ts`](../../packages/squad-cli/src/cli/commands/watch/capabilities/fleet-dispatch.ts) | +| **Watch daemon** | Ralph exposes `--max-concurrent N` for parallel issue triage | [`packages/squad-cli/src/cli-entry.ts`](../../packages/squad-cli/src/cli-entry.ts) | +| **Memory writes** | History-shadow serializes writes per file but parallelizes across agents | [`packages/squad-sdk/src/agents/history-shadow.ts`](../../packages/squad-sdk/src/agents/history-shadow.ts) | + +Squad even ships a marketed docs page (`features/parallel-execution`) and a concept page (`concepts/parallel-work`) — it is a positioned, end-user-visible capability. + +#### Roo-Code — sequential by design + +- [`src/core/task/__tests__/new-task-isolation.spec.ts`](../src/core/task/__tests__/new-task-isolation.spec.ts) **enforces** that if the model emits multiple `new_task` tool uses in one turn, only the first survives — the rest are truncated and rejected with an injected error result. The named test: *"should only consider the first new_task if multiple exist"*. +- [`Task.startSubtask()`](../src/core/task/Task.ts:2380) delegates to a single child via `delegateParentAndOpenChild`; the parent **pauses** while the child runs. Parent ↔ child is strictly serial. +- The Orchestrator mode chains subtasks one at a time. There is no fan-out primitive in the product runtime. +- The only place Roo runs work in parallel is its **evals harness** ([`packages/evals/src/cli/runEvals.ts`](../packages/evals/src/cli/runEvals.ts) uses `PQueue({ concurrency })`) — but that's for benchmarking the agent, not for end-user workflows. + +#### Why this matters: the unlimited-tokens regime + +Once token cost is no longer the bottleneck (Copilot Enterprise seat, internal LLM, generous corporate budget), the scarce resource becomes **wall-clock time**. Parallelism is exactly the lever that converts spare token budget into faster wall-clock results: + +| Scenario | Sequential (Roo) | Parallel (Squad) | +|---|---|---| +| Triage 20 open issues overnight | 20 × ~5 min ≈ 1.7 hr | `--max-concurrent 5` ≈ ~20 min | +| "Refactor parsers across 8 packages" | One package at a time | `team` route fans out, all 8 concurrently | +| Mixed read-only research across a repo | Sequential `read_file` × N | `fleet-dispatch` batches reads into one parallel `/fleet` session | +| Issue with 6 sub-tasks (tests, docs, types, changelog, migrations, README) | 6 sequential subtasks | `wave-dispatch` runs the wave concurrently | + +#### Caveats + +1. **Parallel agents writing to the same workspace can conflict.** Squad mitigates this for memory files via per-path serialization in [`history-shadow.ts`](../../packages/squad-sdk/src/agents/history-shadow.ts), but for source-code edits the burden is on the operator to scope agents to non-overlapping areas (one per package, one per service). +2. **Parallelism amplifies bad prompts.** A confused agent run sequentially wastes one slot of time; ten confused agents in parallel waste ten. Squad's circuit breakers in Ralph help but don't eliminate this. +3. **Roo's serial design is a deliberate safety choice**, not a technical limitation — it keeps every change reviewable. The truncation rule in [`new-task-isolation.spec.ts`](../src/core/task/__tests__/new-task-isolation.spec.ts) could in principle be relaxed, but as of this writing it is enforced. + +--- + +## 5. Features Comparison + +### Roo-Code has, Squad lacks + +- **In-IDE webview UI** (chat, history, settings, marketplace, modes editor, MCP server panel) — none of Squad's UI is graphical +- **Multi-provider model layer** with cost tracking, model lists, image support, prompt caching +- **Full MCP host** with per-mode allow-listing, marketplace +- **Auto-approval system** ([`src/core/auto-approval/`](../src/core/auto-approval)) +- **Codebase indexing** and `codebase_search` semantic search ([`src/services/code-index/`](../src/services/code-index)) +- **Checkpoints** (shadow-git rollback per task) +- **Browser automation** tool +- **Deep i18n** (14+ languages) +- **Cloud features** ([`packages/cloud`](../packages/cloud)) — sign-in, sharing, telemetry +- **Evals harness** ([`packages/evals`](../packages/evals), [`apps/web-evals`](../apps/web-evals)) — Docker-based benchmark runner + +### Squad has, Roo-Code lacks + +- **Team-as-files** — every agent's identity (charter), memory (history), and team decisions are committed into the user's repo so that "anyone who clones the repo gets the team" +- **Casting system** — persistent, thematic naming registry across sessions ([`packages/squad-sdk/src/casting/`](../../packages/squad-sdk/src/casting)) +- **Watch / Ralph daemon** — a long-running polling loop that monitors GitHub issues, dispatches Copilot agents, with circuit-breaker and 4-tier escalation ([`packages/squad-sdk/src/ralph/`](../../packages/squad-sdk/src/ralph)) +- **Cross-squad / multi-squad federation** ([`packages/squad-sdk/src/multi-squad.ts`](../../packages/squad-sdk/src/multi-squad.ts), [`runtime/cross-squad.ts`](../../packages/squad-sdk/src/runtime/cross-squad.ts)) — squads in different repos can discover and delegate work to each other +- **Plugin marketplace and upstream sync** for sharing agents/skills/templates ([`marketplace/`](../../packages/squad-sdk/src/marketplace), [`upstream/`](../../packages/squad-sdk/src/upstream)) +- **OpenTelemetry-native instrumentation** with grpc exporters, agent traces, coordinator traces, metric wiring +- **Aspire dashboard integration** (`squad aspire`) for observability +- **Cost tracker, scheduler, benchmarks, rework rate** as runtime modules +- **Email scrubbing** (`squad scrub-emails`) and PII guards baked into the SDK +- **GitHub Issues / Azure DevOps / Teams comms backends** ([`platform/`](../../packages/squad-sdk/src/platform)) +- **SDK-First mode** — define a team in TypeScript with builder functions and compile to markdown ([`builders/`](../../packages/squad-sdk/src/builders)) + +### Settings / configuration surface + +- **Squad** is configured via markdown files in `.squad/`, an optional [`squad.config.ts`](../../squad.config.ts), CLI flags, and env vars. There is no GUI. +- **Roo-Code** has a sprawling Settings webview with tabs for Providers, Modes, MCP, Auto-Approval, Context, Checkpoints, Notifications, Browser, Terminal, Experiments, Cloud — backed by a `cachedState` buffer (see [`AGENTS.md`](../../AGENTS.md:5)). + +### CLI capabilities + +- **Squad** is **CLI-first** with 17 commands ([`README.md`](../../README.md:99)): `init`, `upgrade`, `triage`/`watch`, `copilot`, `doctor`, `link`, `externalize`, `internalize`, `export`, `import`, `nap`, `aspire`, `scrub-emails`, `plugin marketplace`, `upstream`, etc. +- **Roo-Code** has [`apps/cli`](../apps/cli) but it is a peripheral / experimental surface; the extension is the primary product. + +--- + +## 6. Code Quality & Engineering Practices + +### Testing + +- **Squad** ships **~200 vitest test files** under a flat [`test/`](../../test) directory plus subdirs (`acceptance/`, `ci/`, `cli/`, `helpers/`, `sdk/`, `state/`). Notable: extensive "human-journey" tests ([`test/journey-*.test.ts`](../../test/journey-first-conversation.test.ts)), feature-parity gates, OTel integration tests, hostile-integration tests, stress tests, Playwright smoke tests for docs. +- **Roo-Code** uses vitest with strict workspace isolation rules (per [`.roo/rules/rules.md`](../.roo/rules/rules.md): "Backend tests: `cd src && npx vitest run …`; UI tests: `cd webview-ui && npx vitest run …`"). E2E lives in [`apps/vscode-e2e`](../apps/vscode-e2e). Coverage spans extension, webview, and supporting packages. + +### Lint / format / type-check + +- Squad: ESLint 10, `tsc --noEmit` per package, markdownlint-cli2, cspell. ESM-only. +- Roo-Code: ESLint 9 (shared via [`packages/config-eslint`](../packages/config-eslint)), Turbo orchestrates lint/check-types/test/format, prettier, husky + lint-staged. + +### CI/CD + +- Squad: [`.github/workflows/`](../../.github/workflows) plus a [`.copilot/`](../../.copilot) directory and `copilot-instructions.md` indicating Copilot-native development. +- Roo-Code: [`.github/workflows/`](../.github/workflows) plus shared [`.github/actions/`](../.github/actions), CODEOWNERS, dependabot. Releases use changesets. + +### Documentation + +- Squad: full Astro docs site under [`docs/`](../../docs), README in en/zh, [`CONTRIBUTING.md`](../../CONTRIBUTING.md), [`SECURITY.md`](../../SECURITY.md), CONTRIBUTORS, samples README. +- Roo-Code: lighter top-level docs ([`README.md`](../README.md), [`CONTRIBUTING.md`](../CONTRIBUTING.md), [`AGENTS.md`](../AGENTS.md), [`PRIVACY.md`](../PRIVACY.md), [`SECURITY.md`](../SECURITY.md)) plus 14 localized variants in [`locales/`](../locales). Design docs live under [`docs/design/`](../design). The user-facing product documentation is hosted off-repo. + +### Conventions + +Both use **changesets** for versioning. Squad publishes to npm; Roo-Code publishes to the VS Code Marketplace and OpenVSX. + +--- + +## 7. Notable Divergences & Innovations + +**Where Squad innovates beyond Roo-Code:** + +- **File-backed, persistent multi-agent identity.** Roo's modes are stateless presets; Squad agents accrete project-specific knowledge in `history.md`, recorded in git, replayable and inspectable. +- **Watch/Ralph autonomy.** A polling daemon that auto-triages and dispatches Copilot work, with rate limiting, capability gating, circuit breakers, and overnight quiet hours. Roo-Code has no equivalent autonomous out-of-IDE worker. +- **Cross-squad federation.** Squads in separate repos can discover each other and delegate issues across repository boundaries. +- **OpenTelemetry-first runtime.** First-party traces, metrics, agent and coordinator spans; Aspire dashboard integration. +- **SDK-first programmable team definition.** [`squad.config.ts`](../../squad.config.ts) compiles to the markdown team layout. +- **Pluggable storage providers** including sql.js. + +**Where Roo-Code innovates beyond Squad:** + +- **Provider breadth.** ~30 LLM providers with a uniform abstraction, prompt caching, image support, model lists, and live cost tracking. +- **MCP host depth.** Roo runs MCP servers itself; Squad only configures Copilot's MCP usage. +- **Per-mode tool/file/MCP restrictions** baked into the prompt assembly pipeline. +- **Codebase semantic indexing** ([`src/services/code-index`](../src/services/code-index)) feeding `codebase_search`. +- **Shadow-git checkpoints** for in-task rollback. +- **Webview product surface** with deep settings, marketplace, history, share/sign-in. +- **Evals harness** with Docker compose runner ([`packages/evals/docker-compose.yml`](../packages/evals)). +- **Localization** at near-product-grade depth. + +**Roadmap signals:** + +- Squad's [`README.md`](../../README.md:399) flags SDK-First mode as experimental and the interactive shell as deprecated in favor of `copilot --agent squad`. The `0.9.x` line and the alpha banner imply rapid evolution toward an SDK + watch story. +- Roo-Code's open work (visible from [`docs/design/per-mode-mcp-settings.md`](../design/per-mode-mcp-settings.md) and the open editor tabs around per-mode MCP scoping) signals continued focus on **fine-grained mode capabilities** and tool surface refinement. + +--- + +## 8. Summary Table + +| Attribute | Squad | Roo-Code | +|---|---|---| +| Primary distribution | npm CLI + SDK | VS Code extension (.vsix) | +| Lineage | Original (`@bradygaster`) | Fork of Cline | +| License | MIT | Apache-style (project-specific) | +| Monorepo tooling | npm workspaces | pnpm + Turbo | +| Node engine | `>=22.5.0` | `20.19.2` (pinned) | +| Packages | 2 (`squad-sdk`, `squad-cli`) | 9+ (types, cloud, evals, telemetry, ipc, build, …) | +| Apps in repo | docs site, samples | cli, vscode-e2e, vscode-nightly, web-evals, web-roo-code | +| LLM substrate | GitHub Copilot only | ~30 providers (Anthropic, OpenAI, Bedrock, Vertex, OpenRouter, Ollama, …) | +| Tool surface | SDK tool primitives + hooks | Native + XML tools (read/write/diff/exec/browser/MCP/sub-task) | +| MCP role | Configures Copilot's MCP | Hosts MCP client; per-mode allow-list | +| Agent model | Persistent, named, file-backed agents with `history.md` | Stateless modes with slug + role definition + tool/file/mcp restrictions | +| Sub-agents | Coordinator + fan-out (parallel agents) | `new_task` stack of nested tasks | +| **Parallel execution** ⚡ | **First-class**: fan-out, session pool, `@A @B` syntax, `--max-concurrent`, wave/fleet dispatch | **Sequential by design**: `new_task` isolation enforced; only one subtask at a time | +| Persistence | `.squad/` in git; pluggable storage (fs/in-memory/sql.js); state-backends (git-notes, orphan branch) | VS Code global/workspace state + shadow-git checkpoints | +| Long-running automation | **Ralph watch** (issue triage + dispatch daemon) | None | +| Federation | Cross-squad discovery & delegation | None | +| Marketplace | Plugin marketplace + upstream sync | MCP marketplace | +| Telemetry | OpenTelemetry-native (traces, metrics, exporters) | Custom + PostHog | +| UI | Ink terminal shell (deprecated) + remote-ui; **no product web portal** (Astro site is docs-only, Playwright tests target the docs UX) | Full React 18 webview SPA | +| Settings UI | None (markdown + CLI) | Deep webview settings (Providers, Modes, MCP, …) | +| Cost tracking | Runtime module | Per-provider, per-task | +| Codebase search | No | Semantic index + `codebase_search` | +| Checkpoints | No | Shadow git per task | +| i18n | Light (en + zh README, runtime i18n module) | Deep (14+ locales, both runtime & docs) | +| Evals | benchmarks module | Docker-compose evals harness | +| Versioning | changesets, independent per package | changesets | +| Tests | ~200 vitest files | vitest + Playwright + vscode-e2e across packages | + +--- + +## 9. Conclusions & Recommendations + +### Recommendation by user profile + +| Profile | Recommendation | Why | +|---|---|---| +| Solo dev, **metered** API costs, interactive flow | **Roo-Code primary** | Per-step review, multi-provider, lowest cost-per-task | +| Solo dev, **unlimited Copilot**, wants overnight throughput | **Squad primary** (Roo for interactive sessions) | Parallelism + Ralph turn spare token budget into faster wall-clock results | +| Team with **unlimited Copilot**, GitHub-issue-driven workflow | **Squad primary** | Fan-out + Ralph + `--max-concurrent` + cross-repo federation are uniquely valuable | +| Team needing **diff-by-diff human review** on every change | **Roo-Code** | Squad's parallelism makes per-step review impractical | +| Compliance-sensitive org standardized on Copilot | **Squad** | Inherits Copilot's billing/audit posture for free | +| Org needing **provider portability** (Anthropic, local, Bedrock, …) | **Roo-Code** | ~30 providers vs Squad's Copilot-only | + +### Choose Squad when: + +- You're committed to GitHub Copilot as your model substrate and want to add team-style orchestration on top of it +- You have **effectively unlimited tokens** and want to trade them for **wall-clock speedup via parallel agents** (Squad's standout architectural advantage — see §4j) +- You want **persistent, in-repo, file-backed agents** that other contributors inherit by cloning +- You need **autonomous issue triage and dispatch** (Ralph) running outside an IDE, possibly across repositories +- Observability via OpenTelemetry / Aspire is a hard requirement +- Your workflow is CLI-first or headless (CI runners, devcontainers, remote machines) + +### Choose Roo-Code when: + +- You want a **single-developer, in-IDE coding agent** with a polished UI and per-step diff review +- You need **provider portability** (Anthropic, OpenAI, local Ollama, Bedrock, Vertex, …) rather than Copilot lock-in +- You rely on **MCP servers** as first-class capabilities (running, scoping per mode, surfacing tools) +- You value semantic codebase search, in-task rollback (checkpoints), and fine-grained per-mode tool/file/MCP restrictions +- You need broad localization +- You prefer **safety-via-serialization** — one change at a time, fully reviewable + +### The "unlimited tokens" lens + +For a developer or team with **uncapped token budget** (Copilot Enterprise, internal LLM, generous corporate plan), the calculus shifts meaningfully toward Squad. The bottleneck is no longer dollars per token but **hours per task**, and parallelism is the only architectural feature that directly addresses that. Roo's serial design is a safety win when humans review every step, but a throughput loss when they don't need to. Concretely (see §4j): an overnight 20-issue triage that takes Roo ~1.7 hours can finish in ~20 minutes under Squad with `--max-concurrent 5`. + +This does **not** make Squad a wholesale replacement — Roo's interactive UX, multi-provider abstraction, MCP host depth, and per-step reviewability remain best-in-class. Many teams should reasonably run **both**: Roo for interactive coding sessions, Squad/Ralph for autonomous overnight throughput on the same repo. + +### Cross-pollination opportunities + +**Things Roo-Code could borrow from Squad:** +1. **Parallel `new_task` fan-out (opt-in).** The hardest-hitting borrow. Relax the [`new-task-isolation`](../src/core/task/__tests__/new-task-isolation.spec.ts) rule behind an explicit per-mode/per-task flag (e.g. `parallelSubtasks: true`) and add a session-pool with concurrency limits modeled on Squad's [`session-pool.ts`](../../packages/squad-sdk/src/client/session-pool.ts) and [`fan-out.ts`](../../packages/squad-sdk/src/coordinator/fan-out.ts). Keeps the safe default; unlocks throughput for users who want it. +2. **Persistent agent memory committed to the repo.** A "mode `history.md`" pattern — appended after each task — would give Roo modes longitudinal project knowledge, not just the volatile context window. Pairs naturally with Roo's existing condense system. +3. **Watch/Ralph daemon.** A headless Roo runner that polls GitHub issues / a queue and dispatches modes on a schedule, with circuit-breaker and overnight quiet hours, would extend Roo from an IDE companion to a background teammate. The piece exists conceptually in [`apps/cli`](../apps/cli) but lacks the maturity of Squad's [`packages/squad-sdk/src/ralph/`](../../packages/squad-sdk/src/ralph). +4. **OpenTelemetry-native traces and metrics.** Replace bespoke telemetry with OTel spans for tasks, tool calls, and provider requests, mirroring Squad's [`runtime/otel-*.ts`](../../packages/squad-sdk/src/runtime). + +**Things Squad could borrow from Roo-Code:** +1. **Provider abstraction layer.** Even keeping Copilot as the default, decoupling the agent execution path from `@github/copilot-sdk` (mirroring Roo's [`base-provider.ts`](../src/api/providers/base-provider.ts)) would unlock Anthropic/OpenAI/local model use cases. +2. **First-class MCP host.** Today Squad relies on Copilot's MCP plumbing; promoting MCP servers to citizens of the SDK (like Roo's per-mode allowlist in [`webview-ui/src/components/modes/McpServerRestriction.tsx`](../../webview-ui/src/components/modes/McpServerRestriction.tsx)) would let Squad agents have well-scoped tool capabilities independent of the Copilot agent. +3. **Per-mode/per-agent tool & file restrictions** with regex-driven file gating, as Roo enforces during tool-call validation. Squad has reviewer-lockout and write-guards but not the richer mode-as-policy model. + +Both projects address the same long-term need — making AI agents reliable collaborators on real codebases — from opposite ends. Roo is a **vertically integrated single-agent product**; Squad is a **horizontally integrated multi-agent runtime**. The most interesting future-state for either project lies precisely where each is weakest today. diff --git a/docs/investigation/roo-to-copilot/00-executive-summary.md b/docs/investigation/roo-to-copilot/00-executive-summary.md new file mode 100644 index 00000000000..4f65d2509c5 --- /dev/null +++ b/docs/investigation/roo-to-copilot/00-executive-summary.md @@ -0,0 +1,294 @@ +--- +phase: 9 +status: complete +owner: architect-phase-9 +last_updated: 2026-04-26 +sources: + - docs/investigation/roo-to-copilot/10-roo-inventory.md + - docs/investigation/roo-to-copilot/20-roo-vault-inventory.md + - docs/investigation/roo-to-copilot/30-squad-inventory.md + - docs/investigation/roo-to-copilot/40-copilot-chat-research.md + - docs/investigation/roo-to-copilot/50-copilot-cli-research.md + - docs/investigation/roo-to-copilot/60-gap-analysis.md + - docs/investigation/roo-to-copilot/70-migration-paths.md + - docs/investigation/roo-to-copilot/80-migration-playbook.md + - docs/investigation/roo-to-copilot/90-decision-log.md + - docs/investigation/roo-to-copilot/99-open-questions.md +tldr: | + After a 9-phase investigation, the recommended migration path off Roo-Code is **Path Hybrid** — + Copilot Chat in VS Code for interactive work plus Copilot CLI for automation, BYOK, and + hook-based file-edit policy enforcement, sharing one canonical `.agent.md` per mode and one + `AGENTS.md` per project. Estimated effort: 1–2 weeks for the first project, <1 day per + additional project, with a clean rollback path back to Roo-Code preserved for 30 days. +--- + +# Phase 9 — Executive Summary + +> Parent index: [`README.md`](README.md) · Recommendation source: [`70-migration-paths.md` § 4](70-migration-paths.md#-4--recommendation) · Execution source: [`80-migration-playbook.md`](80-migration-playbook.md) + +> 📌 **This file replaces [`00-plan.md`](00-plan.md) as the entry point.** `00-plan.md` is preserved as a historical record of the investigation methodology; new readers should start here. + +--- + +## § 1 — TL;DR + +**Recommendation: adopt Path Hybrid — Copilot Chat (VS Code) + Copilot CLI (`@github/copilot`), sharing `.agent.md` files and `AGENTS.md` between both surfaces.** Use Chat for interactive IDE work and CLI for anything headless, BYOK, or policy-enforced. Squad and a custom VS Code extension (Path C and Path D) are documented but **not** recommended as starting points. + +- **Headline cost:** 1–2 weeks first-project setup; <1 day per additional project; ~3–5 hours/month ongoing maintenance. No new paid subscription tier required (works on existing Copilot tier; BYOK on CLI requires Pro+). +- **Headline gain:** native cross-tool standards (`AGENTS.md`, `.agent.md`), Windows Credential Manager for MCP secrets, native checkpoints + Fork Conversation, parallel sub-agent dispatch, OpenTelemetry, BYOK to local Ollama on the CLI side. +- **Headline loss:** per-mode `fileRegex` is structurally enforceable only on the CLI surface (prose-only on Chat); Roo-Code's webview UI for visual mode CRUD is gone; `.roo/rules-/` per-mode rules folders inline into agent bodies. +- **Headline risk:** [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) (sub-agent hook bypass) caps the CLI's `fileRegex` mitigation; mitigated today by avoiding `task` dispatch of restricted modes. +- **Single most important next step:** run the vault `fileRegex` audit ([`80 § 1` step 1](80-migration-playbook.md#-1--pre-migration-checklist)) and execute Stage-1 of the playbook (Chat-only scaffold — converts the 17 modes to `.github/agents/*.agent.md`). + +A reader who stops here knows what to do: **read [`80-migration-playbook.md`](80-migration-playbook.md) §§ 0–6 and start Stage 1 today.** + +--- + +## § 2 — The Question + +The user's verbatim ask, restated: *"How do I leave Roo-Code entirely and recreate the same experience using GitHub Copilot — the Chat extension and/or the CLI — preserving my existing [`roo-vault`](../../../../roo-vault) multi-project layout (17 modes, 7 MCP servers, layered rules, symlink-and-commit pattern) on a Windows 11 dev box?"* + +The investigation treated three sub-questions as load-bearing: (a) can Copilot Chat's custom agents + prompt files + MCP fully replace Roo's modes/orchestrator/MCP; (b) does Copilot CLI offer enough automation surface to replace Roo for terminal workflows; (c) does Squad add value as an orchestration layer or is it redundant? The vault is the actual migration unit, not the Roo-Code extension itself — any answer must preserve the multi-project composition that the vault provides. + +--- + +## § 3 — What We Investigated (9-Phase Methodology) + +| Phase | Deliverable | File | Status | +|-------|-------------|------|--------| +| 0 | Investigation plan, methodology, file taxonomy | [`00-plan.md`](00-plan.md) | ✅ | +| 1 | Roo-Code feature inventory (modes, MCP, rules, tools, storage) | [`10-roo-inventory.md`](10-roo-inventory.md) | ✅ | +| 2 | `roo-vault` inventory (17 modes, 7 MCP servers, symlink layout) | [`20-roo-vault-inventory.md`](20-roo-vault-inventory.md) | ✅ | +| 3 | Squad inventory (`@bradygaster/squad-cli` v0.9.1 alpha) | [`30-squad-inventory.md`](30-squad-inventory.md) | ✅ | +| 4 | Copilot Chat (VS Code) research — 4 sub-phases (4a–4d) | [`40-copilot-chat-research.md`](40-copilot-chat-research.md) | ✅ | +| 5 | Copilot CLI research — 5 sub-phases (5a, 5b-i, 5b-ii-A, 5b-ii-B-1/2) | [`50-copilot-cli-research.md`](50-copilot-cli-research.md) | ✅ | +| 6 | Unified gap analysis (~70 rows; Chat vs CLI vs Squad) | [`60-gap-analysis.md`](60-gap-analysis.md) | ✅ | +| 7 | Path scoring (A/B/C/D + Hybrid against 8 weighted criteria) | [`70-migration-paths.md`](70-migration-paths.md) | ✅ | +| 8 | Migration playbook (12 sections + Path B appendix; 24-row validation matrix) | [`80-migration-playbook.md`](80-migration-playbook.md) | ✅ | +| 9 | This summary | [`00-executive-summary.md`](00-executive-summary.md) | ✅ | + +Cross-cutting: [`90-decision-log.md`](90-decision-log.md) (append-only ADRs, ~14 entries) and [`99-open-questions.md`](99-open-questions.md) (Q-001..Q-058, with strikethroughs for resolved items). All findings cite primary sources; no claim is unsourced. + +--- + +## § 4 — The Three Surfaces, Compared + +The investigation evaluated three Copilot surfaces against Roo-Code. Squad layers on top of the CLI but is not an independent surface. + +| Dimension | Copilot Chat (VS Code) | Copilot CLI (`@github/copilot`) | SDK (`@github/copilot-sdk`) | +|---|---|---|---| +| **Identity** | VS Code extension; webview-driven | Standalone Node CLI; TTY-driven | MIT, public preview 0.3.x; transport wrapper over the CLI | +| **Install (Win 11)** | VS Code Marketplace | `npm i -g @github/copilot` | `npm i @github/copilot-sdk` | +| **Subscription** | Free tier eligible | Free tier eligible (BYOK Pro+) | Inherits CLI tier | +| **Modes / agents** | `.github/agents/*.agent.md` + `%APPDATA%\Code\User\prompts\*.agent.md` | `.github/agents/*.agent.md` + `~/.copilot/agents/*.agent.md` (subset schema) | Programmatic via `CopilotSession` | +| **Hooks** | ❌ none (`hooks:` Preview, no enforcement substrate) | ✅ 13 events × `command` and `prompt` types | ✅ in-process `SessionHooks` (6 callbacks) | +| **MCP** | `.vscode/mcp.json` (`servers:` shape + `${input:id}` Credential Manager) | `~/.copilot/mcp-config.json` (`mcpServers:` shape + `${ENV_VAR}`) | File-based discovery | +| **Headless / CI** | ❌ structurally absent (GUI-only) | ✅ `copilot -p '…' -s --no-ask-user --allow-tool=…`, OTel | ✅ programmatic | +| **BYOK (Ollama / Anthropic / Azure direct)** | ❌ G-13 — restricted to GitHub-curated catalog | ✅ `COPILOT_PROVIDER_*` env vars (Pro+) | ✅ same | +| **Vault portability** | 🟡 per-profile `mcp.json` symlinks (Q-026) | ✅ `COPILOT_HOME` env var redirects everything | ✅ `--config-dir` per-invocation | +| **Windows fit** | ✅ native | ✅ native (Node 20+); PowerShell hooks | ✅ extension-host only (no webviews) | +| **Maturity** | GA (custom agents in Preview) | GA (CLI ships ~weekly) | Public preview 0.x — 54 versions in 5 months | + +**One-line takeaway per surface:** Chat owns the IDE ergonomics; CLI owns the automation, hooks, BYOK, and portability; SDK owns the "build your own" extensibility (Path D) but at ~1 engineer-month cost. + +--- + +## § 5 — Gap Landscape + +The unified gap matrix in [`60-gap-analysis.md`](60-gap-analysis.md) covers ~70 feature rows across 12 sections. Severity tally: + +| Surface | 🔴 Blocker | 🟠 Major | 🟡 Minor | ✅ Parity | ➕ Additive (Copilot beats Roo) | +|---|---:|---:|---:|---:|---:| +| **Copilot Chat** | **2** | 8 | 12 | 22 | 4 | +| **Copilot CLI** | **0** | 7 | 11 | 27 | 8 | +| Squad (delta over CLI) | 0 | 0 | 0 | (inherits CLI) | 7 | + +**The two Chat blockers are:** + +| Blocker | What Roo has | Why Chat blocks | Playbook downgrade | +|---|---|---|---| +| **G-1 — `groups[].fileRegex` per-mode edit restriction** ([`60 § B.2`](60-gap-analysis.md#b2-tool-restrictions-per-mode-toolmcpfile-gating)) | `architect` can only edit `.md`, `translate` only `.md/.ts/.json`, `docs-extractor` only paths under `.roo/extraction/`, `docs-writer` only `.md/.txt/.rst/.adoc` — enforced at runtime by Roo | Chat has no hook substrate; the only enforcement is prose ("only edit Markdown") in the agent body | Hybrid downgrades 🔴→🟠 by routing the 4 restricted modes through the CLI surface, where a `preToolUse` PowerShell hook ([`80 § 8`](80-migration-playbook.md#-8--pretooluse-hook-for-fileregex-enforcement-phase-8b-i)) enforces structurally | +| **B.8 row 1 — Headless invocation** | Roo's [`apps/cli/src/agent/json-event-emitter.ts`](../../../apps/cli/src/agent/json-event-emitter.ts) emits NDJSON for CI/cron consumers | Chat is GUI-only; no command-line entry point | Hybrid resolves by including the CLI as a peer surface; the CLI is purpose-built for headless | + +**Top CLI-side major gaps** (not blockers, but worth knowing): CG-1 (no webview UI for mode CRUD), CG-7 (no structured event stream — [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52)), CG-8 (SDK 0.x churn), CG-11 (sub-agent `preToolUse` bypass — [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392)). + +Full row-level matrix and the Top-10 most-important-rows list live in [`60-gap-analysis.md` § D](60-gap-analysis.md#d-top-10-most-important-rows). + +--- + +## § 6 — The Five Migration Paths + +[`70-migration-paths.md`](70-migration-paths.md) scores all five against 8 weighted criteria (capability fidelity 30%, effort 20%, operational risk 15%, day-to-day UX 10%, automation 10%, portability 5%, reversibility 5%, cost 5%): + +| # | Path | One-line description | Score | Rank | +|---|---|---|---:|---:| +| **Hybrid** | **Chat + CLI** | Both surfaces, sharing `.agent.md` and `AGENTS.md`; CLI owns hooks/BYOK | **3.90** | 🥇 1st | +| B | CLI only | Terminal-first; `preToolUse` hook closes G-1; loses webview UX | 3.70 | 2nd | +| D | Vault-as-VSIX | Custom VS Code extension via `@github/copilot-sdk`; closes G-1/G-2 cleanly at ~1 engineer-month cost | 3.25 | 3rd | +| C | CLI + Squad | Path B + Squad's parallel orchestration; alpha-stability tax (CG-12) | 3.20 | 4th | +| A | Chat only | IDE-native; G-1 unmitigated; no headless | 3.10 | 5th | + +**Winner:** **Path Hybrid (3.90)**, beating the runner-up (Path B) by 0.20 points — a margin driven by Hybrid's parity-or-better score on every criterion (no value below 3) and the structural fact that the CLI is *additive*, not exclusive, with respect to the Chat surface. + +--- + +## § 7 — Why Path Hybrid + +Six reasons, each tied to a specific finding from earlier phases: + +- **Closes G-1 where it matters.** The vault's 4 regex-bound modes (`docs-writer`, `translate`, `docs-extractor`, `architect`, confirmed by the [`80 § 4`](80-migration-playbook.md#-4--17-mode-mapping-table) audit) get structural enforcement via the CLI's `preToolUse` hook ([`80 § 8`](80-migration-playbook.md#-8--pretooluse-hook-for-fileregex-enforcement-phase-8b-i)). The remaining 13 IDE-bound modes use Chat with prose-only enforcement — acceptable because they have no `fileRegex` to enforce in the first place. +- **Single canonical `.agent.md` per mode, both surfaces consume.** The CLI's `.agent.md` schema is a **strict subset** of Chat's ([`80 § 7.2`](80-migration-playbook.md#-72--agentmd-schema-diff-cli-vs-chat)); a Chat-valid file is automatically CLI-valid. Author once, symlink twice — no drift. +- **MCP is the only thing that genuinely duplicates.** CG-3 forks the schema (Chat = `servers:`, CLI = `mcpServers:`). Hybrid resolves Q-050 by treating Chat's `.vscode/mcp.json` as the source of truth and generating the CLI mirror via [`80 § 9`](80-migration-playbook.md#-9--mcp-canonical-source-generator-phase-8b-i-resolves-q-050)'s PowerShell script, run as a pre-commit hook. +- **`COPILOT_HOME` solves vault portability cleanly.** A single env var redirects every CLI sub-path (settings, agents, hooks, MCP, sessions) to the vault. Massively simpler than Chat's per-profile-id `mcp.json` symlink dance. Closes Q-008. +- **BYOK retained on the CLI side.** `COPILOT_PROVIDER_BASE_URL=http://localhost:11434/v1` routes the CLI to local Ollama (Pro+); Chat falls back to the GitHub-curated catalog. Hybrid users who care about local models use them where they can be used. +- **Defers the SDK / VSIX risk.** Path D (build a custom extension on `@github/copilot-sdk`) remains documented as a Stage-3 escalation, not a starting point. Hybrid avoids the 0.x SDK churn (54 versions in 5 months) and the ~1-engineer-month build cost while keeping that door open if `fileRegex` enforcement gaps later become genuinely painful. + +--- + +## § 8 — What You Get / What You Lose + +| You **get** (additive over Roo) | You **lose** (regressions vs Roo) | +|---|---| +| Native `AGENTS.md` ingestion (W-5; cross-tool with Claude Code, Cursor, Codex, Gemini CLI) | Per-mode `groups[].fileRegex` enforced *in the IDE* (G-1; CLI hook only) | +| MCP secrets via Windows Credential Manager + `${input:id}` first-run prompt (W-4) | `.roomodes` workspace overrides as a discrete file format (replaced by `.github/agents/*.agent.md`) | +| Native checkpoints + Fork Conversation (W-8) — strictly better than Roo's per-task git-shadow rollback | Hot-reload of mode edits in a webview — Copilot needs `Developer: Reload Window` for some changes | +| Parallel sub-agent dispatch (W-7) — Roo's serial enforcement was a *limitation* | Roo-Code's mature `ModesView.tsx` / `McpServerRestriction.tsx` GUI for visual mode CRUD (CG-1) | +| `Kind(arg)` permission grammar on CLI (CW-12) — `shell(git:*)`, `write(./src/**)`; finer than Roo's per-server `alwaysAllow` | Roo's NDJSON event emitter (28+ event types) — Copilot CLI is text-only until [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) | +| BYOK on CLI side (CW-2) — local Ollama, Anthropic direct, Azure OpenAI | BYOK on Chat side (G-13 stays open) — IDE work uses GitHub-hosted models | +| `COPILOT_HOME` single-env-var portability (CW-6) | Per-profile VS Code `mcp.json` still needs a PowerShell helper (Q-026) | +| OpenTelemetry export via standard OTLP env vars (CW-3) | Roo's `update_todo_list` re-injection on every turn (Q-049 — no Copilot equivalent) | +| Session full-text search via SQLite FTS5 on CLI (CW-4) | `.roo/rules-/` per-mode rules folder (G-2 — must inline into agent body) | +| Official upgrade path; weekly CLI releases; org-policy ceiling on Chat (W-10) | Roo-Code's bespoke Marketplace tab for community modes (replaced by Agent Plugins Preview, gated by `chat.plugins.enabled`) | +| Copilot subscription pricing (no separate Roo licence to think about) | Roo-Code's mature `update_todo_list` ergonomics for long orchestrator tasks | + +Net assessment: **Copilot Chat + CLI ships more capability than it removes.** The losses are real but bounded; the gains compound over time as Microsoft/GitHub iterate on the surfaces. + +--- + +## § 9 — Migration Plan at a Glance + +The full playbook is in [`80-migration-playbook.md`](80-migration-playbook.md). Effort sizing per section, with the critical path called out: + +| § | Section | Effort | Critical path? | +|---:|---|---|---| +| 0 | Overview & scope | S | — | +| 1 | Pre-migration checklist (`fileRegex` audit, MCP source decision, backup, disable Roo) | S | **🚨 audit gates everything** | +| 2 | Shared assets (`AGENTS.md`, `.agent.md`, `.instructions.md`) | M | ✅ | +| 3 | Chat-side configuration (`.vscode/mcp.json`, user `mcp.json`, toolsets, `copilot-instructions.md`) | M | ✅ | +| 4 | 17-mode mapping table (1 row per vault mode) | M | ✅ | +| 5 | Stage-1 execution (8 PowerShell steps; reload + verify) | M | ✅ | +| 6 | Hand-off to Phase 8b | S | — | +| 7 | CLI-side configuration (`~/.copilot/`, `COPILOT_HOME`, BYOK env vars, `mcp-config.json`) | M | ✅ | +| 8 | `preToolUse` hook for the 4 `fileRegex` modes (PowerShell ref impl + JSON policy table) | L | **🚨 sole G-1 mitigation** | +| 9 | MCP canonical-source generator (Q-050; `scripts/generate-cli-mcp.ps1`) | M | ✅ | +| 10 | Setup automation (`setup-copilot-vault.ps1`, `setup-copilot-project.ps1`, pre-commit hook) | L | — | +| 11 | Validation matrix (24 tests across Chat / CLI / hooks / cross-cutting) | M | **🚨 cutover gate** | +| 12 | Rollback plan (full + 4 partial scenarios; sign-off checklist) | S | — | +| App. B | Path B (CLI-only) fallback playbook | S | — | + +**Total estimated effort:** **1–2 weeks** for the first project (Stage 1 ≈ 3–7 days Chat scaffold; Stage 2 ≈ 2–5 days CLI + hooks); **<1 day per additional project**; **~3–5 hours/month** ongoing maintenance (track upstream issues, regenerate MCP on edits). + +Effort scale: **S** = ≤ ½ day · **M** = ½ – 2 days · **L** = 2 – 5 days. + +**Critical path** (must complete in order, cannot parallelise): § 1 audit → § 2–4 shared assets → § 5 Stage-1 verify → § 7–8 CLI + hook → § 11 validation → cutover. § 9 generator and § 10 automation can land in parallel with § 8 hook authoring. + +--- + +## § 10 — Risks & Mitigations + +Top 5 risks, ordered by severity × likelihood: + +| # | Risk | Severity | Likelihood | Mitigation | Owner action | +|---|---|---|---|---|---| +| 1 | **CG-11 — sub-agent `preToolUse` bypass** ([`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392)). `task`-dispatched restricted modes leak past the hook | 🟠 Major | High (active bug) | Avoid dispatching `architect` / `translate` / `docs-extractor` / `docs-writer` as sub-agents; orchestrator agent body forbids it; warning paragraph in each restricted agent body ([`80 § 8.6`](80-migration-playbook.md#-86--caveats--known-limitations)) | Pin the issue; review monthly; drop the convention when fixed | +| 2 | **SDK 0.x churn** if user later considers Path D. 54 versions in 5 months; runtime patcher needed at squad ([`90 2026-04-26 17:58`](90-decision-log.md)) | 🟠 Major | Certain (so long as 0.x) | Defer Path D; if pursued, mirror Squad's adapter-types pattern + `as Parameters[N]` casts | Re-evaluate when SDK reaches 1.0 | +| 3 | **Copilot pricing changes** disrupt BYOK or agent-mode tier gating | 🟠 Major | Low–Medium | Keep CLI BYOK env vars set; fall back to local Ollama if Pro+ becomes uneconomic; preserve cross-tool `.agent.md` portability (W-5) | Re-verify [§ 1 step 3](80-migration-playbook.md#-1--pre-migration-checklist) tier table quarterly | +| 4 | **Microsoft renames `.agent.md` again** (it was `.chatmode.md` until early 2026) | 🟡 Minor | Low | Vault file naming is mechanical; rename is a `Get-ChildItem` one-liner; track [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515) and the Phase-4d release-version provenance (Q-016) | Monitor Insider release notes monthly | +| 5 | **Vault drift between Chat and CLI** if MCP edits land in the CLI mirror by accident | 🟡 Minor | Medium | Pre-commit hook regenerates `mcp-config.json` from `.vscode/mcp.json` on every commit ([`80 § 10.3`](80-migration-playbook.md#-103--pre-commit-hook-stub-closes--93-todo)); CLI mirror documented as build output | Audit `git status` of `mcp-config.json` after edits | + +Lower-tier risks (filed but not in the top 5): pwsh cold-start latency (Q-039 / T-X-05), OneDrive symlink behaviour (Q-058), `AGENTS.local.md` dual-surface support (Q-051 — verification recipe shipped). + +--- + +## § 11 — Open Questions Worth Watching + +Of the ~58 questions filed in [`99-open-questions.md`](99-open-questions.md) (most resolved), the 5 most consequential remaining for the user: + +| ID | Question | Why it matters | When to revisit | +|---|---|---|---| +| **Q-047** | Vault's actual `fileRegex` usage breadth — how many modes use `fileRegex` *and* are dispatched as sub-agents from the orchestrator? | Determines whether G-1 stays 🟠 or re-escalates to 🔴 on the CLI side under CG-11 | **Before Stage-1** (audit command in [`80 § 1`](80-migration-playbook.md#-1--pre-migration-checklist) step 1) | +| **Q-049** | Roo's `update_todo_list` re-injection has no Copilot equivalent | Long orchestrator tasks may lose "always-on" todo context; affects daily UX | After 30 days of Hybrid usage; file feature request if missed | +| **Q-054** | Does the CLI export `$env:COPILOT_AGENT` to hook subprocesses? | If yes, [`80 § 8.3`](80-migration-playbook.md#-83--active-agent-discovery-cg-13-mitigation)'s sidecar wrapper can be dropped — simpler hook | During Stage-2 (probe in 5 minutes per the question body) | +| **Q-057** | Hook latency baseline on the user's box — < 400 ms target per `enforce-file-regex.ps1` call (T-X-05) | If > 1 s, escalate to a compiled hook (Go binary); affects every restricted-mode tool call | During Stage-1 → Stage-2 cutover | +| **Q-058** | Symlink behaviour under OneDrive / corporate redirected profiles | Affects multi-machine / enterprise vault deployment | First cross-machine deployment | + +Two upstream issues to subscribe to (GitHub bell icon): [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) (sub-agent hook bypass) and [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) (structured event stream). When either ships, revisit the score table in § 6. + +--- + +## § 12 — Recommended Next Steps + +A concrete, sequenced rollout. Each step references the playbook section that owns it. + +| # | Step | Effort | Playbook reference | +|---:|---|---|---| +| 1 | **Today.** Run the vault `fileRegex` audit (Q-047) and confirm the 4-mode hook coverage list. Verify Copilot subscription tier at `https://github.com/settings/copilot`. Verify `node -v` ≥ 22.5. Subscribe to [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) and [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) | ½ day | [`80 § 1`](80-migration-playbook.md#-1--pre-migration-checklist) | +| 2 | **Day 1.** Take the dated backup (script in `§ 1` step 5). Disable (do **not** uninstall) the Roo-Code extension globally | 1 hour | [`80 § 1`](80-migration-playbook.md#-1--pre-migration-checklist) step 5–6 | +| 3 | **Days 2–4 — Stage 1.** Convert all 17 vault modes to `.github/agents/*.agent.md` per the worked architect example. Author / copy `AGENTS.md`. Convert `.roo/rules/` to `.github/instructions/*.instructions.md`. Convert `.roo/mcp.json` and global `mcp_settings.json` to the Chat schema. Reload VS Code; run the smoke tests in [`§ 5`](80-migration-playbook.md#-5--step-by-step-phase-8a-execution) step 7–8 | 3 days | [`80 §§ 2–5`](80-migration-playbook.md#-2--shared-assets-work-in-both-chat-and-cli) | +| 4 | **Days 5–6 — CLI bootstrap.** Install `@github/copilot`. Set `COPILOT_HOME` to the vault. Symlink `~/.copilot/agents/` → vault. Set 4 MCP env vars (`GITHUB_PAT`, `TAVILY_API_KEY`, `CONTEXT7_API_KEY`, `ADO_PAT`). Optionally set `COPILOT_PROVIDER_*` for Ollama BYOK | 2 days | [`80 § 7`](80-migration-playbook.md#-7--cli-side-configuration-phase-8b-i) | +| 5 | **Days 7–9 — Hook + generator.** Author `enforce-file-regex.ps1` and `mode-policies.json` for the 4 restricted modes. Author `generate-cli-mcp.ps1` and run it once. Wire up the `~/.copilot/hooks.json` registration | 3 days | [`80 §§ 8–9`](80-migration-playbook.md#-8--pretooluse-hook-for-fileregex-enforcement-phase-8b-i) | +| 6 | **Day 10.** Run `setup-copilot-vault.ps1` and `setup-copilot-project.ps1` to install symlinks and pre-commit hook. Verify with `Test-CanSymlink` pre-flight | ½ day | [`80 § 10`](80-migration-playbook.md#-10--setup-automation-phase-8b-ii) | +| 7 | **Day 11 — Cutover gate.** Execute the entire 24-row validation matrix. Record T-X-05 latency baseline (closes Q-057). Confirm T-CLI-CG11 reproduces (or doesn't — if not, the upstream bug is fixed and the playbook updates) | 1 day | [`80 § 11`](80-migration-playbook.md#-11--validation-matrix-phase-8b-ii) | +| 8 | **Day 11+.** Begin daily-driver use of Path Hybrid. Keep Roo-Code disabled but installed for 30 days. File a decision-log entry capturing any unexpected friction | ongoing | [`80 § 12`](80-migration-playbook.md#-12--rollback-plan-phase-8b-ii) sign-off criteria | +| 9 | **Day 41.** After 30 days of clean operation, **uninstall Roo-Code**. Archive `globalStorage\rooveterinaryinc.roo-cline\` to backup folder. Investigation officially closed at the user's end | ½ day | [`80 § 12.4`](80-migration-playbook.md#-124--sign-off-criteria-for-rollback-complete) (inverse) | +| 10 | **Ongoing — monthly.** Re-run validation matrix. Audit chat history for G-1 prose violations (>2 in 30 days = trigger Path B per Appendix B.1). Refresh issue subscriptions | 1 hour/month | [`80 § 11.3`](80-migration-playbook.md#-113--cross-cutting-tests-5-rows) "When to run what" | + +**The single most consequential next step is #1 — without the `fileRegex` audit, Stage 1 cannot scope the hook coverage list.** Everything else flows from that count. + +--- + +## § 13 — Decision Record (Top 5) + +Condensed from [`90-decision-log.md`](90-decision-log.md). Format: decision · rationale · alternative rejected · date. + +| # | Decision | Rationale | Alternative rejected | Date | +|---|---|---|---|---| +| 1 | **Adopt Path Hybrid (Chat + CLI) as primary** | Highest weighted score (3.90); closes G-1 where it matters; bounded effort; max reversibility | Path A (3.10 — G-1 unmitigated, no headless); Path C (3.20 — alpha tax); Path D (3.25 — ~1 month build cost) | 2026-04-26 18:27 | +| 2 | **Chat's `.vscode/mcp.json` is the canonical MCP source; CLI mirror is generated** (Q-050) | IDE-centric vault; `.vscode/mcp.json` is what the "MCP: Open Workspace Configuration" command edits; preserves Credential Manager UX | CLI-as-truth (loses `${input:id}` first-run prompt); third canonical YAML (extra file no tool reads) | 2026-04-26 18:45 | +| 3 | **Accept CG-11 as a known limitation; enforce by convention** (avoid `task` dispatch of restricted modes) | The 4 restricted modes are typically boot agents, not sub-agents; vault's actual usage pattern minimises blast radius; convention is enforceable via prose discipline; auto-resolves when [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) ships | Path D for the 4 modes (~1 month for one bug); abandon CLI side (loses headless + BYOK) | 2026-04-26 18:45 | +| 4 | **Symlink, do not copy, for vault → consumer paths** | Single source of truth; multi-machine portability; mirrors existing `roo-vault\setup-vault.ps1` pattern; `Test-CanSymlink` pre-flight surfaces the admin/Developer-Mode requirement clearly | Copy (forks edits, breaks multi-machine); junctions only (silent OneDrive degradation) | 2026-04-26 18:52 | +| 5 | **Phase 8 split into 8a (Chat) + 8b-i (CLI core) + 8b-ii (automation/validation/rollback)** | Lets Stage-1 work begin immediately without blocking on full CLI side; clean hand-off boundaries documented in inline TODOs | Monolithic Phase 8 (delays Stage 1); ship CLI first (worse onboarding for IDE-centric user) | 2026-04-26 18:35 → 18:52 | + +--- + +## § 14 — Appendix: File Map + +Every memory file in the investigation, with status and approximate line count. + +| File | Status | Purpose | Approx. lines | +|---|---|---|---:| +| [`README.md`](README.md) | ✅ index | Phase status badges, file map, usage rules | ~80 | +| [`00-executive-summary.md`](00-executive-summary.md) | ✅ Phase 9 | **This file — START HERE** | ~370 | +| [`00-plan.md`](00-plan.md) | ✅ historical | Original 9-phase investigation plan and methodology | ~200 | +| [`10-roo-inventory.md`](10-roo-inventory.md) | ✅ Phase 1 | Roo-Code feature inventory (modes, MCP, rules, tools, storage) | ~300 | +| [`20-roo-vault-inventory.md`](20-roo-vault-inventory.md) | ✅ Phase 2 | `roo-vault` layout (17 modes, 7 MCP servers, symlink-and-commit pattern) | ~250 | +| [`30-squad-inventory.md`](30-squad-inventory.md) | ✅ Phase 3 | Squad inventory (alpha v0.9.1; CLI-driver, no `vscode.lm`) | ~200 | +| [`40-copilot-chat-research.md`](40-copilot-chat-research.md) | ✅ Phase 4 | Custom agents, instructions, prompt files, tool sets, MCP, agent mode, Gap Catalog (G-/W-) | ~900 | +| [`50-copilot-cli-research.md`](50-copilot-cli-research.md) | ✅ Phase 5 | Identity/install, agent loop, MCP, Hooks (preToolUse verdict), Skills, Scripting, full SDK exports, CLI Gap Catalog (CG-/CW-) | ~1,400 | +| [`60-gap-analysis.md`](60-gap-analysis.md) | ✅ Phase 6 | Unified gap matrix (~70 rows × 12 sections); severity tally; top-10 callout | ~270 | +| [`70-migration-paths.md`](70-migration-paths.md) | ✅ Phase 7 | A/B/C/D + Hybrid scoring against 8 weighted criteria; recommendation = Path Hybrid | ~510 | +| [`80-migration-playbook.md`](80-migration-playbook.md) | ✅ Phase 8 | Concrete file-by-file Hybrid migration; 12 sections + Appendix B; 24-row validation matrix | ~1,770 | +| [`90-decision-log.md`](90-decision-log.md) | ✅ closed | Append-only ADRs (~14 entries); investigation closed by Phase 9 retrospective | ~700 | +| [`99-open-questions.md`](99-open-questions.md) | ✅ active | Q-001..Q-058; resolved items struck through with link to resolving entry | ~130 | + +**Total investigation footprint:** ~7,100 lines of memory across 13 files, all cross-linked, all citing primary sources. + +--- + +## Cross-links + +- Recommendation source: [`70-migration-paths.md` § 4](70-migration-paths.md#-4--recommendation) +- Execution: [`80-migration-playbook.md`](80-migration-playbook.md) +- Decisions: [`90-decision-log.md`](90-decision-log.md) +- Open questions: [`99-open-questions.md`](99-open-questions.md) +- Vault entry points: [`../../../../roo-vault/global-settings/custom_modes.yaml`](../../../../roo-vault/global-settings/custom_modes.yaml) · [`../../../../roo-vault/global-settings/mcp_settings.json`](../../../../roo-vault/global-settings/mcp_settings.json) · [`../../../../roo-vault/setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1) diff --git a/docs/investigation/roo-to-copilot/00-plan.md b/docs/investigation/roo-to-copilot/00-plan.md new file mode 100644 index 00000000000..4492868fdb8 --- /dev/null +++ b/docs/investigation/roo-to-copilot/00-plan.md @@ -0,0 +1,146 @@ +--- +phase: plan +status: not-started +owner: tbd +last_updated: 2026-04-26 +sources: [] +--- + +# Investigation Plan — Roo-Code → GitHub Copilot + +> Read [`README.md`](README.md) and [`90-decision-log.md`](90-decision-log.md) before editing this file. + +## Goal (verbatim) + +Replicate the Roo-Code experience — **modes, orchestrator, MCP, custom prompts, rules, memory** — in **GitHub Copilot Chat** and/or **Copilot CLI**, possibly via **Squad**; ultimately **leave Roo-Code**. + +## Non-goals + +- Building a new AI coding agent from scratch. +- Forking or maintaining Roo-Code long-term. +- Evaluating non-Copilot agents (Cursor, Cline, Continue, Aider, etc.) beyond brief mention. +- Migrating teammates / org-wide tooling — this is a single-developer migration. + +## Success Criteria + +The investigation is "done" when **all** of the following hold: + +1. A clear, recorded **decision** in [`90-decision-log.md`](90-decision-log.md) on path A/B/C/D (Chat-only / CLI-only / Squad-mediated / hybrid). +2. A working **migration playbook** in [`80-migration-playbook.md`](80-migration-playbook.md) that maps every Roo concept the user actually relies on to a concrete Copilot artifact. +3. A populated **gap analysis** in [`60-gap-analysis.md`](60-gap-analysis.md) with no gap rated `blocker` left without a workaround or accepted-loss note. +4. The user can disable the Roo-Code extension and continue working on existing projects in [`roo-vault`](../../../../roo-vault) without functional regression beyond accepted losses. + +## Constraints + +- **OS**: Windows 11. +- **Editor**: Visual Studio Code (stable). +- **Multi-project layout**: User maintains [`roo-vault`](../../../../roo-vault) at `c:/git/roo-vault` containing global settings, per-project overrides, setup scripts, and memory/notes conventions. +- **Squad**: Source available at `c:/git/squad` for inspection. +- **Roo workspace**: Active development copy at `c:/git/Roo-Code` (this repo). +- **No paid tier assumptions** beyond the user's existing GitHub Copilot subscription tier (to be confirmed in Phase 4). +- **Preserve memory/context**: existing project memory conventions must survive migration. + +## 9-Phase Plan + +### Phase 1 — Inventory the Roo-Code experience +**Artifact:** [`10-roo-inventory.md`](10-roo-inventory.md) + +Concrete questions to answer: +- What built-in modes exist and what is each one's system prompt shape? +- Schema of `.roomodes` and the global `custom_modes.yaml`? +- How does the Orchestrator mode delegate to other modes (boomerang/subtask mechanics)? +- How is MCP wired: global `mcp_settings.json` vs project `.roo/mcp.json`, per-mode `allowedMcpServers`? +- Custom prompt/rule loading order: `.roo/rules/`, `AGENTS.md`, mode-specific rules. +- What memory/context features exist (todo list, reminders, condensing, memory bank patterns)? +- Native tool surface — full enumerated list of tools each mode can call. +- Where are settings stored on disk on Windows (globalStorage paths, workspace `.roo/`)? +- Which webview-UI features (mode picker, MCP toggles, context settings) are worth replicating? + +### Phase 2 — Inventory the roo-vault layout +**Artifact:** [`20-roo-vault-inventory.md`](20-roo-vault-inventory.md) + +Concrete questions: +- Top-level directory layout of `c:/git/roo-vault`. +- What lives in `global-settings/` (e.g. `custom_modes.yaml`)? +- How are per-project overrides organized under `projects//.roo/`? +- What does `setup/setup_dev_box.ps1` install/configure? +- Memory/notes conventions: file names, locations, lifecycle. +- MCP server inventory: which servers are registered globally vs per-project. + +### Phase 3 — Investigate Squad +**Artifact:** [`30-squad-inventory.md`](30-squad-inventory.md) + +Concrete questions: +- What is Squad? (Project description, README, package.json, entry points.) +- Architecture — is it an extension, CLI, library, orchestrator? +- Relationship to Copilot — does it wrap, extend, or replace Copilot APIs? +- Relationship to Roo-Code — overlap, divergence, shared concepts. +- Feature overlap matrix vs Roo features identified in Phase 1. +- Verdict: use as primary / use partially / don't use. + +### Phase 4 — Research GitHub Copilot Chat in VS Code +**Artifact:** [`40-copilot-chat-research.md`](40-copilot-chat-research.md) + +Concrete questions: +- Custom chat modes — `.chatmode.md` file format, location, capabilities, limits. +- `.github/copilot-instructions.md` — scope, precedence, multi-file support. +- Prompt files — `.prompt.md` format, invocation, parameters. +- MCP support — config file location, per-mode allowlists?, transport types. +- Tool sets — defining and scoping tools per mode. +- Agent mode — capabilities, sub-agent / delegation support. +- Chat participants & extension API — can custom extensions add modes/tools? +- Storage locations on Windows (globalStorage, workspace settings). +- Known limits and gaps vs Roo. + +### Phase 5 — Research GitHub Copilot CLI +**Artifact:** [`50-copilot-cli-research.md`](50-copilot-cli-research.md) + +Same shape as Phase 4 but for the CLI: +- Install/auth, agent loop semantics, MCP support, custom instructions, scripting/automation hooks, storage locations, limits. + +### Phase 6 — Gap analysis matrix +**Artifact:** [`60-gap-analysis.md`](60-gap-analysis.md) + +Build a single table: **Roo feature → Copilot Chat equivalent → Copilot CLI equivalent → Squad equivalent → gap severity → workaround → notes**. Severity scale: `none / minor / major / blocker`. + +### Phase 7 — Migration path options +**Artifact:** [`70-migration-paths.md`](70-migration-paths.md) + +Evaluate four candidate paths with pros, cons, effort, risk, prerequisites: +- **Path A:** Copilot Chat only. +- **Path B:** Copilot CLI only. +- **Path C:** Squad-mediated (Squad as orchestrator over Copilot). +- **Path D:** Hybrid (Chat for interactive, CLI for automation, Squad optionally for orchestration). + +### Phase 8 — Concrete migration playbook +**Artifact:** [`80-migration-playbook.md`](80-migration-playbook.md) + +File-by-file mappings: +- `.roomodes` → Copilot `.chatmode.md` files (+ schema converter notes). +- `.roo/rules/*` → `.github/copilot-instructions.md` (+ split strategy). +- Global `custom_modes.yaml` → user-scope chatmode location. +- `mcp.json` (global + project) → Copilot MCP config. +- Memory bank conventions → Copilot prompt files + instruction files. +- `roo-vault` layout → equivalent Copilot multi-project layout. +- Step-by-step migration order with rollback notes. + +### Phase 9 — Executive summary + decision record +**Artifact:** [`90-decision-log.md`](90-decision-log.md) (final entry) + summary section in [`README.md`](README.md). + +Final entry must include: chosen path, rationale, accepted losses, follow-up tasks. + +## Methodology Rules + +- **Cite sources.** Every factual claim sourced from the web includes URL + access date. Every claim about Roo internals references a file path with line number where possible (e.g. [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts)). +- **Quote primary docs** verbatim where ambiguity matters; paraphrase only when summarizing. +- **Note uncertainty explicitly** with `> ⚠️ Uncertain:` callouts rather than silent guesses. +- **Prefer official Microsoft / GitHub documentation** over blog posts; mark community sources as such. +- **Append-only decision log.** Never rewrite history; supersede with a new dated entry. +- **One decision per log entry.** Bundling decisions hides rationale. +- **Date everything.** ISO-8601. + +## Cross-links + +- Index: [`README.md`](README.md) +- Decision log: [`90-decision-log.md`](90-decision-log.md) +- Open questions: [`99-open-questions.md`](99-open-questions.md) diff --git a/docs/investigation/roo-to-copilot/10-roo-inventory.md b/docs/investigation/roo-to-copilot/10-roo-inventory.md new file mode 100644 index 00000000000..86241256084 --- /dev/null +++ b/docs/investigation/roo-to-copilot/10-roo-inventory.md @@ -0,0 +1,226 @@ +--- +phase: 1 +status: complete +owner: architect-subtask +last_updated: 2026-04-26 +sources: + - packages/types/src/mode.ts + - packages/types/src/__tests__/mode-allowedMcpServers.spec.ts + - schemas/roomodes.json + - .roomodes + - .roo/mcp.json + - src/core/config/CustomModesManager.ts + - src/core/prompts/system.ts + - src/core/prompts/sections/custom-instructions.ts + - src/core/prompts/sections/capabilities.ts + - src/core/prompts/tools/native-tools/mcp_server.ts + - src/core/task/build-tools.ts + - src/services/roo-config/index.ts + - docs/design/per-mode-mcp-settings.md + - docs/analysis/squad-vs-roo-comparison.md + - webview-ui/src/components/modes/ModesView.tsx + - webview-ui/src/components/modes/McpServerRestriction.tsx + - AGENTS.md +--- + +# Phase 1 — Roo-Code Experience Inventory + +> Parent plan: [`00-plan.md`](00-plan.md) · Index: [`README.md`](README.md) + +A complete inventory of the Roo-Code features the user relies on, derived from local source. Every claim is anchored to a file path with a line number. + +## Modes & Built-in Mode Definitions + +Built-in modes are declared as the `DEFAULT_MODES` array in [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:169). Their schema is the `modeConfigSchema` defined at [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:96), which requires `slug`, `name`, `roleDefinition`, and `groups`, and optionally accepts `whenToUse`, `description`, `customInstructions`, `source` (`global` | `project`), and `allowedMcpServers`. + +| Slug | Name | Default tool groups | File restrictions | Notable role / instructions | +|---|---|---|---|---| +| `architect` | 🏗️ Architect | `read`, `edit`, `mcp` | `edit` restricted to `\.md$` (markdown only) | Plan-and-design role; instructions force the agent to gather context, ask clarifying questions, build a todo list with `update_todo_list`, draw Mermaid diagrams, then `switch_mode`. Source: [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:171-181) | +| `code` | 💻 Code | `read`, `edit`, `command`, `mcp` | None | Generic software engineer; no `customInstructions`. Source: [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:182-191) | +| `ask` | ❓ Ask | `read`, `mcp` | None (read-only by absence of `edit`) | Q&A assistant; instructed not to switch into implementing code unless asked. Source: [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:192-203) | +| `debug` | 🪲 Debug | `read`, `edit`, `command`, `mcp` | None | Systematic debugger; instructed to enumerate 5–7 hypotheses, narrow to 1–2, add logs, ask the user to confirm before fixing. Source: [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:204-215) | +| `orchestrator` | 🪃 Orchestrator | `[]` (empty — no tool groups) | n/a | Coordinator that delegates via `new_task` to other modes; explicit instructions to bundle "all necessary context", "clearly defined scope", "supersede" clause. Has access to `new_task` and `attempt_completion` because those tools are not gated by the `read`/`edit`/`command`/`mcp`/`modes`/`browser` group system (see [`src/core/prompts/tools/filter-tools-for-mode.ts`](../../../src/core/prompts/tools/filter-tools-for-mode.ts)). Source: [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:216-227) | + +Group names allowed by the schema: `read`, `edit`, `command`, `mcp`, `modes`, `browser` (deprecated, silently stripped via `groupEntryArraySchema` preprocess at [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:91-94) and the `deprecatedToolGroups` list referenced at line 3). Each `groups` entry can be either a bare string or a `[name, { fileRegex, description }]` tuple, where `fileRegex` is validated as a real regex via the refinement at [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:13-26). + +## Custom Modes (`.roomodes`, global `custom_modes.yaml`) + +### Schema + +[`schemas/roomodes.json`](../../../schemas/roomodes.json:1) is a JSON Schema (draft-07) that validates the `.roomodes` file. Required mode fields: `slug` (regex `^[a-zA-Z0-9-]+$`), `name`, `roleDefinition`, `groups`. Optional: `whenToUse`, `description`, `customInstructions`, `source` (`"global"` | `"project"`), `rulesFiles` (array of `{relativePath, content}` for export/import), and `allowedMcpServers` (added at [`schemas/roomodes.json`](../../../schemas/roomodes.json:84-90)). `additionalProperties: false`. + +The `allowedMcpServers` field has identical semantics in TypeScript and JSON-Schema land — see the Zod definition at [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:105) and the dedicated test suite [`packages/types/src/__tests__/mode-allowedMcpServers.spec.ts`](../../../packages/types/src/__tests__/mode-allowedMcpServers.spec.ts:1). + +### Files on disk + +- **Project-scoped:** `/.roomodes` (YAML; this repo's actual file is at [`.roomodes`](../../../.roomodes:1) and overrides every built-in mode plus adds `translate`, `issue-fixer`, `pr-fixer`, `merge-resolver`, `issue-investigator`, `issue-writer`, `docs-extractor`). +- **Global (user-scope, Windows):** `%APPDATA%\Code\User\globalStorage\rooveterinaryinc.roo-cline\settings\custom_modes.yaml` — i.e. `C:\Users\\AppData\Roaming\Code\User\globalStorage\rooveterinaryinc.roo-cline\settings\custom_modes.yaml`. Confirmed by the open-tab path in this workspace's environment and by the `mockSettingsPath`/`mockRoomodes` constants used in [`src/core/config/__tests__/CustomModesManager.spec.ts`](../../../src/core/config/__tests__/CustomModesManager.spec.ts:97). The file is YAML, structured `{ customModes: [ ... ] }`. + +### Loader & precedence + +`CustomModesManager` at [`src/core/config/CustomModesManager.ts`](../../../src/core/config/CustomModesManager.ts:1) loads both files. The merge logic is **`.roomodes` wins** — see [`src/core/config/CustomModesManager.ts`](../../../src/core/config/CustomModesManager.ts:301-302) (`Merge modes from both sources (.roomodes takes precedence)`) and the watcher block at [`src/core/config/CustomModesManager.ts`](../../../src/core/config/CustomModesManager.ts:323-335) (`// .roomodes takes precedence`). The `source` field is auto-stamped: project for `.roomodes`, global for the YAML settings file ([`src/core/config/CustomModesManager.ts`](../../../src/core/config/CustomModesManager.ts:210-216), [`src/core/config/CustomModesManager.ts`](../../../src/core/config/CustomModesManager.ts:389-394)). + +Resolution order **as observed in code**: +1. Project `.roomodes` (highest). +2. Global `custom_modes.yaml`. +3. Built-in `DEFAULT_MODES` (lowest fallback when no override exists). + +A built-in slug (e.g. `code`) can be replaced wholesale by a project or global definition with the same slug. + +## Orchestrator Behavior + +Orchestrator is defined in two places: +- The built-in entry at [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:216-227) (`groups: []` — meaning the only tools available are the always-on ones: `new_task`, `switch_mode`, `attempt_completion`, `ask_followup_question`, `update_todo_list`). +- A project override at [`.roomodes`](../../../.roomodes:2-31) which is byte-identical to the built-in. + +The delegation contract is encoded as plain prose in `customInstructions`. Each `new_task` invocation must include: full context, scope, "do only this work" clause, instruction to call `attempt_completion` with a thorough summary, and a "these instructions supersede general mode instructions" clause ([`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:225)). + +The native tool implementing delegation is `new_task` at [`src/core/prompts/tools/native-tools/new_task.ts`](../../../src/core/prompts/tools/native-tools/new_task.ts:1) (registered via [`src/core/prompts/tools/native-tools/index.ts`](../../../src/core/prompts/tools/native-tools/index.ts:1) and dispatched in `Task.startSubtask()` at [`src/core/task/Task.ts`](../../../src/core/task/Task.ts:2380)). Sub-task runtime semantics are **strictly serial**: only the first `new_task` per assistant turn is honoured; additional ones are truncated and rejected with an injected error result. Test-enforced at [`src/core/task/__tests__/new-task-isolation.spec.ts`](../../../src/core/task/__tests__/new-task-isolation.spec.ts:1) (named test: *"should only consider the first new_task if multiple exist"*). Cited by [`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:174-178). + +The parent task pauses; the child runs to completion or `attempt_completion`; the parent resumes with the child's result string. This is the boomerang loop. + +## MCP Integration + +### Configuration files + +- **Global, user-scope (Windows):** `%APPDATA%\Code\User\globalStorage\rooveterinaryinc.roo-cline\settings\mcp_settings.json` — confirmed by the open-tab path in this workspace. Top-level shape `{ "mcpServers": { : , ... } }`. Each server config has `command` + `args` (stdio), or `type: "streamable-http"` + `url` + optional `headers` (HTTP), and shared keys `disabled`, `alwaysAllow`, `env`. Real example shape visible in [`../roo-vault/global-settings/mcp_settings.json`](../../../../roo-vault/global-settings/mcp_settings.json:1) (a checked-in copy of the same structure). +- **Project-scope:** `/.roo/mcp.json` — same schema. This repo's file is at [`.roo/mcp.json`](../../../.roo/mcp.json:1) and registers `ado` (stdio via `npx @azure-devops/mcp`) and `git` (stdio via `docker run mcp/git`). + +### Transports supported + +- `stdio` — `command` + `args` (e.g. `npx`, `docker`). +- `streamable-http` — `type: "streamable-http"` + `url` + optional `headers` (e.g. `context7`, `microsoft-learn`). + +### Server discovery & precedence + +`McpHub.getServers()` (referenced from [`src/core/prompts/tools/native-tools/mcp_server.ts`](../../../src/core/prompts/tools/native-tools/mcp_server.ts:19) and described in [`docs/design/per-mode-mcp-settings.md`](../../design/per-mode-mcp-settings.md:26)) deduplicates global vs project servers with **project-wins** semantics. + +### Per-mode `allowedMcpServers` + +Defined as `z.array(z.string()).optional()` at [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:105). Semantics, per [`docs/design/per-mode-mcp-settings.md`](../../design/per-mode-mcp-settings.md:80-84): + +- **Omitted** → all servers available (backward-compatible default). +- **Empty `[]`** → MCP capability text is excluded from the system prompt and **no** MCP server tools are injected — even if the `mcp` group is in `groups`. +- **Populated** → only listed servers are visible to that mode. + +Filtering is implemented in `getMcpServerTools()` at [`src/core/prompts/tools/native-tools/mcp_server.ts`](../../../src/core/prompts/tools/native-tools/mcp_server.ts:14-25): a `Set` of allowed names filters `mcpHub.getServers()` before tool definitions are emitted. The allowlist is plumbed in from `buildNativeToolsArrayWithRestrictions()` at [`src/core/task/build-tools.ts`](../../../src/core/task/build-tools.ts:128-133): + +```ts +const modeConfig = getModeBySlug(mode ?? defaultModeSlug, customModes) +const allowedMcpServers = modeConfig?.allowedMcpServers +const mcpTools = getMcpServerTools(mcpHub, allowedMcpServers) +``` + +System-prompt rendering of MCP capability text is gated by both the `mcp` group **and** non-empty filtered server set — exercised by tests at [`src/core/prompts/__tests__/system-prompt.spec.ts`](../../../src/core/prompts/__tests__/system-prompt.spec.ts:579-639) (`"should exclude MCP capability text when allowedMcpServers is empty array"` and `"should include MCP capability text when allowedMcpServers matches connected servers"`). The capability string itself lives in [`src/core/prompts/sections/capabilities.ts`](../../../src/core/prompts/sections/capabilities.ts:10-16). + +### Tool-name shaping + +MCP tool names are sanitized for OpenAI-compatible function-name rules via `buildMcpToolName(server.name, tool.name)` at [`src/core/prompts/tools/native-tools/mcp_server.ts`](../../../src/core/prompts/tools/native-tools/mcp_server.ts:42). Duplicates are deduplicated (first-wins; project servers come first because of `McpHub.getServers()` ordering — [`src/core/prompts/tools/native-tools/mcp_server.ts`](../../../src/core/prompts/tools/native-tools/mcp_server.ts:44-48)). + +### Per-tool enable/allow + +Each MCP tool can be individually disabled via `tool.enabledForPrompt === false` ([`src/core/prompts/tools/native-tools/mcp_server.ts`](../../../src/core/prompts/tools/native-tools/mcp_server.ts:36-38)). Each server config carries an `alwaysAllow` array that suppresses approval prompts for listed tool names (e.g. [`.roo/mcp.json`](../../../.roo/mcp.json:11-67)). + +## Custom Prompts / Rules + +The rule loader is `addCustomInstructions()` at [`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts:382). It composes the system-prompt's "USER'S CUSTOM INSTRUCTIONS" block from several sources, in this order: + +1. **Mode-specific rules** — for the active mode ``, the loader walks the `.roo/rules-/` directory in each entry returned by `getRooDirectoriesForCwd()` (i.e. global first, then project) ([`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts:409-419)). Files are concatenated in directory order. +2. **Legacy fallback** — if no `rules-/` directory contributes content, the loader looks for `/.roorules-` and then `/.clinerules-` ([`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts:426-434)). +3. **`AGENTS.md` family** — `loadAgentRules()` at [`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts:347-379) reads `AGENTS.md` (and the alternate `AGENT.md`) plus `AGENTS.local.md` from the project root and, when `enableSubfolderRules` is on, every directory that contains a `.roo/`. The repo-level workspace file is [`AGENTS.md`](../../../AGENTS.md:1). +4. **Generic rules** — `loadRuleFiles()` at [`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts:206) reads `/.roo/rules/**/*` (global and project; subfolders included when enabled). Symlinks are followed to a max depth (`MAX_DEPTH = 5`, line 46). + +### Directory resolution + +`getRooDirectoriesForCwd(cwd)` returns `[ getGlobalRooDirectory(), getProjectRooDirectoryForCwd(cwd) ]` — i.e. `[ os.homedir() + ".roo", cwd + ".roo" ]` ([`src/services/roo-config/index.ts`](../../../src/services/roo-config/index.ts:26-29) and [`src/services/roo-config/index.ts`](../../../src/services/roo-config/index.ts:104-106)). On Windows, the global rules directory is therefore `C:\Users\\.roo\` — **not** the VS Code globalStorage path. (Important: this is distinct from `custom_modes.yaml` and `mcp_settings.json`, which live under VS Code globalStorage.) + +`getAllRooDirectoriesForCwd()` ([`src/services/roo-config/index.ts`](../../../src/services/roo-config/index.ts:305-319)) extends this with subfolder `.roo/` directories discovered via ripgrep. Order: global → project → subfolders alphabetically (test at [`src/services/roo-config/__tests__/index.spec.ts`](../../../src/services/roo-config/__tests__/index.spec.ts:462-476)). + +`loadConfiguration()` at [`src/services/roo-config/index.ts`](../../../src/services/roo-config/index.ts:402-441) makes the override semantics explicit: when both global and project copies of the same relative-path file exist, the merged content concatenates them with the literal header `# Project-specific rules (override global):`. + +### Conflict resolution + +There is no key-level merge. Files are concatenated in the order: mode-specific (or legacy fallback) → AGENTS.md (root + subfolder) → generic `.roo/rules/`. Later content does not erase earlier content; it is simply appended. For overlapping advice the model decides — there is no static-resolution layer. + +## Memory / Context Features + +Roo ships several first-class context-management features, all observable in source: + +- **Todo list tool** — `update_todo_list` is a dedicated native tool ([`src/core/prompts/tools/native-tools/update_todo_list.ts`](../../../src/core/prompts/tools/native-tools/update_todo_list.ts:1)). Several modes (architect, issue-writer) explicitly require it as the planning surface ([`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:180); [`.roomodes`](../../../.roomodes:138-145)). +- **Reminders** — every prompt turn re-injects a "REMINDERS" table containing the current todo list (visible in this very session's `environment_details`), powered by the same `update_todo_list` plumbing. +- **Context condensing (auto-summarization)** — when a request's prevContextTokens exceed an effective threshold, `summarizeConversation()` is called from [`src/core/context-management/index.ts`](../../../src/core/context-management/index.ts:306-331) and emits a `condense_context` say-event with `{summary, cost, prevContextTokens, newContextTokens, condenseId}` ([`src/core/task/Task.ts`](../../../src/core/task/Task.ts:1733-1739)). Nested condensing is supported via `condenseId`/`condenseParent` linkage (test at [`src/core/condense/__tests__/nested-condense.spec.ts`](../../../src/core/condense/__tests__/nested-condense.spec.ts:1)). +- **Sliding-window truncation fallback** — if condensing fails or is disabled, `truncateConversation()` removes oldest messages and emits `sliding_window_truncation` ([`src/core/task/Task.ts`](../../../src/core/task/Task.ts:3924-3943)). +- **Checkpoints (shadow git)** — diff-style rollback of workspace edits inside a single task; subsystem at [`src/core/checkpoints/`](../../../src/core/checkpoints) (cited in [`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:147)). +- **Skills system** — markdown SKILL.md files loaded on demand via the `skill` tool ([`src/core/prompts/tools/native-tools/skill.ts`](../../../src/core/prompts/tools/native-tools/skill.ts:1)). Mandatory pre-flight skill applicability check is part of architect mode's system prompt (visible in this turn's prompt under ``). +- **No formal "memory bank"** — there is no built-in long-term project memory beyond the rules/AGENTS.md/skill files and shadow-git checkpoints. The user's `roo-vault` adds external memory conventions (Phase 2). + +## Tool Surface (Native Tools) + +Native tools live under [`src/core/prompts/tools/native-tools/`](../../../src/core/prompts/tools/native-tools/) and are registered via [`src/core/prompts/tools/native-tools/index.ts`](../../../src/core/prompts/tools/native-tools/index.ts:1). The full file inventory (excluding `__tests__/` and the helper `converters.ts` / `mcp_server.ts` / `index.ts`): + +| Tool | File | Group gate (typical) | +|---|---|---| +| `access_mcp_resource` | [`access_mcp_resource.ts`](../../../src/core/prompts/tools/native-tools/access_mcp_resource.ts:1) | `mcp` + has-resources check ([`filter-tools-for-mode.ts`](../../../src/core/prompts/tools/filter-tools-for-mode.ts:305-307)) | +| `apply_diff` | [`apply_diff.ts`](../../../src/core/prompts/tools/native-tools/apply_diff.ts:1) | `edit` | +| `apply_patch` | [`apply_patch.ts`](../../../src/core/prompts/tools/native-tools/apply_patch.ts:1) | `edit` | +| `ask_followup_question` | [`ask_followup_question.ts`](../../../src/core/prompts/tools/native-tools/ask_followup_question.ts:1) | always | +| `attempt_completion` | [`attempt_completion.ts`](../../../src/core/prompts/tools/native-tools/attempt_completion.ts:1) | always | +| `codebase_search` | [`codebase_search.ts`](../../../src/core/prompts/tools/native-tools/codebase_search.ts:1) | `read` (gated by CodeIndexManager availability) | +| `edit_file` | [`edit_file.ts`](../../../src/core/prompts/tools/native-tools/edit_file.ts:1) | `edit` | +| `edit` | [`edit.ts`](../../../src/core/prompts/tools/native-tools/edit.ts:1) | `edit` (alias / variant) | +| `execute_command` | [`execute_command.ts`](../../../src/core/prompts/tools/native-tools/execute_command.ts:1) | `command` | +| `generate_image` | [`generate_image.ts`](../../../src/core/prompts/tools/native-tools/generate_image.ts:1) | experimental | +| `list_files` | [`list_files.ts`](../../../src/core/prompts/tools/native-tools/list_files.ts:1) | `read` | +| `new_task` | [`new_task.ts`](../../../src/core/prompts/tools/native-tools/new_task.ts:1) | always (delegation primitive) | +| `read_command_output` | [`read_command_output.ts`](../../../src/core/prompts/tools/native-tools/read_command_output.ts:1) | `command` | +| `read_file` | [`read_file.ts`](../../../src/core/prompts/tools/native-tools/read_file.ts:1) | `read` (description varies with `supportsImages`) | +| `run_slash_command` | [`run_slash_command.ts`](../../../src/core/prompts/tools/native-tools/run_slash_command.ts:1) | always | +| `search_files` | [`search_files.ts`](../../../src/core/prompts/tools/native-tools/search_files.ts:1) | `read` | +| `search_replace` | [`search_replace.ts`](../../../src/core/prompts/tools/native-tools/search_replace.ts:1) | `edit` | +| `skill` | [`skill.ts`](../../../src/core/prompts/tools/native-tools/skill.ts:1) | always (skills system) | +| `switch_mode` | [`switch_mode.ts`](../../../src/core/prompts/tools/native-tools/switch_mode.ts:1) | always (gated by `modes` group only when used to *create* modes) | +| `update_todo_list` | [`update_todo_list.ts`](../../../src/core/prompts/tools/native-tools/update_todo_list.ts:1) | always (toggleable per-config via `todoListEnabled`) | +| `write_to_file` | [`write_to_file.ts`](../../../src/core/prompts/tools/native-tools/write_to_file.ts:1) | `edit` | + +Plus dynamic MCP tools synthesized by [`mcp_server.ts`](../../../src/core/prompts/tools/native-tools/mcp_server.ts:1) (one entry per `__`). + +The build pipeline that filters this set per mode is [`src/core/task/build-tools.ts`](../../../src/core/task/build-tools.ts:83). Final selection passes through `filterNativeToolsForMode()` and `filterMcpToolsForMode()` from [`src/core/prompts/tools/filter-tools-for-mode.ts`](../../../src/core/prompts/tools/filter-tools-for-mode.ts:1). The `experiments.customTools` flag enables loading user-authored tools from `/tools/` ([`src/core/task/build-tools.ts`](../../../src/core/task/build-tools.ts:139-147)). + +## Settings Storage Paths (Windows) + +| Artifact | Path | Source of fact | +|---|---|---| +| Global custom modes | `%APPDATA%\Code\User\globalStorage\rooveterinaryinc.roo-cline\settings\custom_modes.yaml` | Open-tab path in this workspace; `mockSettingsPath` constants in [`src/core/config/__tests__/CustomModesManager.spec.ts`](../../../src/core/config/__tests__/CustomModesManager.spec.ts:97) | +| Global MCP settings | `%APPDATA%\Code\User\globalStorage\rooveterinaryinc.roo-cline\settings\mcp_settings.json` | Open-tab path in this workspace | +| Global rules / shared content | `%USERPROFILE%\.roo\` (i.e. `C:\Users\\.roo\`) | `getGlobalRooDirectory()` returns `path.join(os.homedir(), ".roo")` at [`src/services/roo-config/index.ts`](../../../src/services/roo-config/index.ts:26-29) | +| Global agents directory | `%USERPROFILE%\.agents\` | `getGlobalAgentsDirectory()` at [`src/services/roo-config/index.ts`](../../../src/services/roo-config/index.ts:53-56) | +| Project custom modes | `\.roomodes` (YAML) | [`src/core/config/CustomModesManager.ts`](../../../src/core/config/CustomModesManager.ts:320); constant `ROOMODES_FILENAME` | +| Project MCP servers | `\.roo\mcp.json` | [`.roo/mcp.json`](../../../.roo/mcp.json:1) | +| Project rules (generic) | `\.roo\rules\**` | [`src/services/roo-config/index.ts`](../../../src/services/roo-config/index.ts:104-106) + [`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts:206) | +| Project rules (per mode) | `\.roo\rules-\**` | [`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts:411-419) | +| Project AGENTS.md | `\AGENTS.md` (also `AGENT.md`, `AGENTS.local.md`) | [`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts:294-319) | +| Project ignore | `\.rooignore` | mentioned in this turn's environment under `.rooignore` heading; read by `RooIgnoreController` | +| Custom tools | `\tools\` (when `experiments.customTools` is enabled) | [`src/core/task/build-tools.ts`](../../../src/core/task/build-tools.ts:140) | + +## Webview UI Features Worth Replicating + +The mode/MCP UX lives under [`webview-ui/src/components/modes/`](../../../webview-ui/src/components/modes/) and is invoked by `ModesView.tsx`: + +- **Mode picker / editor** ([`webview-ui/src/components/modes/ModesView.tsx`](../../../webview-ui/src/components/modes/ModesView.tsx:1)) — searchable list of modes (built-in + project + global), edit form for `name`, `roleDefinition`, `whenToUse`, `description`, `customInstructions`, `groups` checkboxes (`read`, `edit`, `command`, `mcp`, `modes`, `browser`), per-`edit` group `fileRegex` field, and a Save button. Built-ins can be overridden from this UI; the override is written to the appropriate scope (project `.roomodes` or global `custom_modes.yaml`). +- **Per-mode MCP allowlist** ([`webview-ui/src/components/modes/McpServerRestriction.tsx`](../../../webview-ui/src/components/modes/McpServerRestriction.tsx:1)) — when the `mcp` group is checked, a "Restrict to specific MCP servers" toggle appears; when on, a checklist of currently connected MCP server names (sourced from the global mcpServers state) is shown and selections map to `allowedMcpServers`. Behavior matches the design spec at [`docs/design/per-mode-mcp-settings.md`](../../design/per-mode-mcp-settings.md:172-180). +- **Delete-mode confirmation dialog** ([`webview-ui/src/components/modes/DeleteModeDialog.tsx`](../../../webview-ui/src/components/modes/DeleteModeDialog.tsx:1)) — destructive-action confirmation that also offers to delete the `.roo/rules-/` directory. + +Adjacent webview features (not under `modes/` but noted in [`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:148)) worth flagging: + +- **MCP server panel** with health/enable toggles, connection logs, and a "Restart" action (settings-tab UI). +- **Context settings** — toggles for `todoListEnabled`, autoCondense thresholds, partial-reads, etc. +- **Prompts UI** — view/edit per-mode `customInstructions` and per-support-prompt overrides. +- **Marketplace tab** for downloading community modes — see [`src/services/marketplace/MarketplaceManager.ts`](../../../src/services/marketplace/MarketplaceManager.ts:255). + +These are the user-visible surfaces that any Copilot-based replacement will need analogues for (Phase 6 will rate which exist in Copilot Chat / CLI). + +## Cross-links + +- [`00-plan.md`](00-plan.md) · [`60-gap-analysis.md`](60-gap-analysis.md) · [`80-migration-playbook.md`](80-migration-playbook.md) +- Companion analysis: [`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md) +- MCP design: [`docs/design/per-mode-mcp-settings.md`](../../design/per-mode-mcp-settings.md) diff --git a/docs/investigation/roo-to-copilot/20-roo-vault-inventory.md b/docs/investigation/roo-to-copilot/20-roo-vault-inventory.md new file mode 100644 index 00000000000..3050f2a8a6a --- /dev/null +++ b/docs/investigation/roo-to-copilot/20-roo-vault-inventory.md @@ -0,0 +1,246 @@ +--- +phase: 2 +status: complete +owner: architect-subtask +last_updated: 2026-04-26 +sources: + - ../../../../roo-vault/README.md + - ../../../../roo-vault/setup-vault.ps1 + - ../../../../roo-vault/setup/setup_dev_box.ps1 + - ../../../../roo-vault/global-settings/custom_modes.yaml + - ../../../../roo-vault/global-settings/mcp_settings.json + - ../../../../roo-vault/projects/Roo-Code/.roomodes + - ../../../../roo-vault/projects/Roo-Code/.roo/mcp.json + - ../../../../roo-vault/projects/pgsql-orion/.roomodes + - ../../../../roo-vault/plans/api-keys-known-risk.md +--- + +# Phase 2 — `roo-vault` Inventory + +> Parent plan: [`00-plan.md`](00-plan.md) · Index: [`README.md`](README.md) + +The user's "vault" lives at `c:/git/roo-vault` (sibling to `Roo-Code`). It is a checked-in personal mono-repo of Roo configuration that is **symlinked into VS Code's Roo settings directory** and into each project's `.roo/` so that one file edit propagates everywhere. + +> All paths in this file are relative to the vault root unless noted. The clickable links use a `../../../../` prefix to escape the `Roo-Code/docs/investigation/roo-to-copilot/` location and reach the sibling `roo-vault/` directory. + +## Top-Level Layout + +Recursive listing of `c:/git/roo-vault` (top-level + first-level for project subdirs): + +``` +roo-vault/ +├── .gitignore +├── README.md ← architecture overview +├── setup-vault.ps1 ← per-project Windows setup script +├── setup-vault.sh ← per-project Linux/macOS setup script +│ +├── global-settings/ +│ ├── custom_modes.yaml ← 19 custom modes (symlinked to globalStorage) +│ └── mcp_settings.json ← gitignored; 7 MCP servers (3 enabled, 4 disabled) +│ +├── shared-modes/ ← long-form mode instruction bodies +│ ├── architect.md code-reviewer.md design-reviewer.md +│ ├── devops.md docs-writer.md pull-requestor.md +│ ├── review-addresser.md security.md task-filer.md +│ +├── shared-rules/ ← per-mode rule fragments +│ ├── rules-architect/ (2 files) +│ ├── rules-code/ (1 file: no-commit.md) +│ ├── rules-design-reviewer/ (1 file) +│ ├── rules-orchestrator/ (3 files) +│ ├── rules-pull-requestor/ (2 files) +│ └── rules-tester/ (1 file: testing-exemptions.md) +│ +├── shared-skills/ ← reusable SKILL.md packages +│ ├── archive-plan-doc/SKILL.md +│ ├── code-reviewer/SKILL.md +│ └── generate-plan-docs/SKILL.md +│ +├── plans/ ← decision/audit/design memory +│ ├── api-keys-known-risk.md +│ ├── orchestrator-rules-audit-2026-04-14.md +│ └── archive/ +│ ├── config-audit-2026-04-12.md +│ ├── config-audit-2026-04-13.md +│ ├── config-audit-remediation.md +│ └── mode-standardization-design.md +│ +├── projects/ +│ ├── argus/ ← scaffold only (.roo/, no .roomodes) +│ ├── hyper-v-mcp-server/ +│ │ ├── .roomodes (empty: customModes: []) +│ │ └── .roo/ +│ ├── orcasql-breadth/ +│ │ ├── .roomodes +│ │ └── .roo/ +│ ├── pgsql-orion/ +│ │ ├── .roomodes (3 ADO-flavoured project modes) +│ │ └── .roo/ +│ └── Roo-Code/ +│ ├── .roomodes (2 project overrides: devops, pr-fixer) +│ └── .roo/ (mcp.json + commands/ + rules-/ + skills/ + shared-modes/ + shared-rules/ + shared-skills/) +│ +└── setup/ + ├── move_wsl_folder.ps1 + ├── setup_dev_box.ps1 ← Windows dev-box bootstrap (NOT the vault setup) + ├── setup_linux_box.sh + ├── setup_ubuntu_box.sh + └── tests/ +``` + +Confirmed via `list_files` (recursive) on [`../../../../roo-vault`](../../../../roo-vault). + +## Global Settings — `global-settings/custom_modes.yaml` + +The vault's authoritative copy of the global custom modes is at [`../../../../roo-vault/global-settings/custom_modes.yaml`](../../../../roo-vault/global-settings/custom_modes.yaml:1). It contains **19 custom mode definitions**. Most use `customInstructions` of the form `Load and follow the shared … instructions from .roo/shared-modes/.md.` so the body lives once and is reused via the symlinked `shared-modes/`. + +| # | Slug | Display name | Purpose | Groups | File restrictions | `allowedMcpServers` | +|---|---|---|---|---|---|---| +| 1 | `docs-writer` | 📝 Documentation Writer | Author/maintain README, API docs, ADRs | `read`, `edit`, `browser`, `command`, `mcp` | `edit` → `\.(md\|txt\|rst\|adoc)$` | (omitted → all) | +| 2 | `security` | 🔒 Security Analyst | Threat modelling, vulnerability review | `read`, `browser`, `command`, `mcp` | none | (omitted) | +| 3 | `design-reviewer` | 🏛️ Design Reviewer | Review designs / roadmaps; **never implements** | `read`, `browser`, `mcp` | none | (omitted) | +| 4 | `review-addresser` | 🔧 Review Addresser | Address PR feedback (scoped fixes) | `read`, `edit`, `command`, `mcp` | none | (omitted) | +| 5 | `code-reviewer` | 🔍 Code Reviewer | Formal code review; **READ-ONLY**, no edits | `read`, `command` | n/a (no edit group) | (omitted) | +| 6 | `task-filer` | 📋 Task Filer | File issues / work items into GitHub or ADO | `read`, `command`, `mcp` | none | (omitted) | +| 7 | `builder` | 🔨 Builder | Build system specialist | `read`, `edit`, `command`, `mcp` | none | (omitted) | +| 8 | `tester` | 🧪 Tester | Run / interpret tests across frameworks | `read`, `edit`, `command`, `mcp` | none | (omitted) | +| 9 | `translate` | 🌐 Translate | i18n / localisation file maintenance | `read`, `command`, `edit` (regex-restricted) | `edit` → `(.*\.(md\|ts\|tsx\|js\|jsx)$\|.*\.json$)` | (omitted) | +| 10 | `issue-fixer` | 🔧 Issue Fixer | Resolve GitHub issues end-to-end | `read`, `edit`, `command` | none | (omitted) | +| 11 | `merge-resolver` | 🔀 Merge Resolver | Resolve PR merge conflicts using git history | `read`, `edit`, `command`, `mcp` | none | (omitted) | +| 12 | `docs-extractor` | 📚 Docs Extractor | Extract raw facts for documentation | `read`, `edit` (regex), `command`, `mcp` | `edit` → `\.roo/extraction/.*\.(yaml\|json\|md)$` | (omitted) | +| 13 | `issue-investigator` | 🕵️ Issue Investigator | Triage GitHub issues; propose solutions | `read`, `command`, `mcp` | none | (omitted) | +| 14 | `issue-writer` | 📝 Issue Writer | Author well-formed GitHub issues | `read`, `command`, `mcp` | none | (omitted) | +| 15 | `code` | 💻 Code | **Override** of built-in `code` | `read`, `edit`, `command`, `mcp` | none | **`[]`** (empty → MCP disabled even though group is present) | +| 16 | `ask` | ❓ Ask | **Override** of built-in `ask` | `read`, `mcp` | none | `ado`, `context7`, `tavily`, `microsoft-learn` | +| 17 | `debug` | 🪲 Debug | **Override** of built-in `debug` | `read`, `edit`, `command`, `mcp` | none | `ado`, `git` | +| 18 | `architect` | 🏗️ Architect | **Override** of built-in `architect` | `read`, `edit` (regex), `mcp` | `edit` → `\.md$` | `git`, `context7`, `tavily`, `ado` | +| 19 | `pull-requestor` | 🚀 Pull Requestor | PR creation / management | `read`, `edit`, `command`, `mcp` | none | `ado`, `git` | +| 20 | `orchestrator` | 🪃 Orchestrator | **Override** of built-in `orchestrator` | `read` only | n/a | (omitted) | +| 21 | `devops` | ⚙️ DevOps Engineer | CI/CD, infra, containers, cloud | `read`, `edit`, `command`, `mcp` | none | `github`, `git` | + +(Counted 21 entries in the YAML, not 19. The vault README mentions 14–15 modes; the file has grown.) + +Cited at [`../../../../roo-vault/global-settings/custom_modes.yaml`](../../../../roo-vault/global-settings/custom_modes.yaml:1) (line ranges per mode visible in the file). + +### Notable patterns in the global modes + +- **Body indirection** — almost every mode's `customInstructions` says `Load and follow the shared … instructions from .roo/shared-modes/.md.`. The body lives in `shared-modes/.md` and is symlinked into each project's `.roo/shared-modes/`. This means changing one file updates every project's behaviour. +- **`code` is intentionally MCP-less** — `allowedMcpServers: []` ([`../../../../roo-vault/global-settings/custom_modes.yaml`](../../../../roo-vault/global-settings/custom_modes.yaml:271)) to keep raw coding sessions free of tool-schema bloat. Reasoning matches the design at [`docs/design/per-mode-mcp-settings.md`](../../design/per-mode-mcp-settings.md:6-10) (context bloat / 128-tool limit). +- **`code-reviewer` is `read+command` only** — explicit READ-ONLY enforcement so the agent cannot modify code under review. +- **`orchestrator` is `read` only** — the user's override demotes the built-in (which has `groups: []`) to `read`-only as a deliberate guardrail; all real work must go through `new_task` delegation. + +## Per-Project Overrides + +Per-project `/.roomodes` files **only contain modes that override or add to the global set**; for example [`../../../../roo-vault/projects/Roo-Code/.roomodes`](../../../../roo-vault/projects/Roo-Code/.roomodes:1) defines just `devops` and `pr-fixer`. The global `code`, `ask`, etc. apply unless project overrides them. + +| Project | `.roomodes` overrides | `.roo/mcp.json` adds | Notes | +|---|---|---|---| +| `Roo-Code` | `devops`, `pr-fixer` (lines 1-22) | `ado` (Azure DevOps stdio) + `git` (mcp/git via Docker) | Project-level `.roo/` includes [`commands/`](../../../../roo-vault/projects/Roo-Code/.roo/commands), [`rules-/`](../../../../roo-vault/projects/Roo-Code/.roo) (XML rule packs per mode), [`skills/`](../../../../roo-vault/projects/Roo-Code/.roo/skills), and symlinks to `shared-modes/`, `shared-rules/`, `shared-skills/`. | +| `pgsql-orion` | `builder`, `tester`, `devops` (lines 1-121) | (project mcp.json adds `ado` for `msdata` ADO project + `git`) | Multi-language Postgres-fork project; `tester` mode declares 10 in-mode skill names (rust-tester, pytest-tester, dotnet-tester, …). `allowedMcpServers` set on `tester` to `[context7, git, microsoft-learn, tavily]`. | +| `hyper-v-mcp-server` | `customModes: []` (empty) | (per-project mcp.json) | Uses global modes only. Task filing routed to global `task-filer` + project `.roo/skills/file-task/SKILL.md`. | +| `orcasql-breadth` | `customModes: []` per the vault README | (per-project mcp.json with ADO config) | Same pattern as hyper-v-mcp-server but ADO backend. | +| `argus` | (no `.roomodes`) | (project `.roo/` scaffold) | Bare scaffold. | + +### Convention: per-project `.roo/` structure + +The convention (verified from [`../../../../roo-vault/projects/Roo-Code/.roo`](../../../../roo-vault/projects/Roo-Code/.roo)) is: + +``` +.roo/ +├── mcp.json # project MCP servers +├── commands/ # slash-command markdown files (cli-release.md, commit.md, release.md, …) +├── guidance/ # long-form guidance docs (e.g. roo-translator.md) +├── plans/ # archived plans / design notes (this directory) +├── rules/ # generic rules: rules.md +├── rules-/ # per-mode rule packs (XML or .md) +│ ├── rules-architect/ +│ ├── rules-code/ # use-safeWriteJson.md +│ ├── rules-debug/ # cli.md +│ ├── rules-docs-extractor/ # 1_extraction_workflow.xml, 2_verification_workflow.xml, 3_output_format.xml +│ ├── rules-issue-fixer/ # 9 numbered .xml files +│ ├── rules-issue-investigator/ # 6 numbered .xml files +│ ├── rules-issue-writer/ # 4 numbered .xml files +│ ├── rules-merge-resolver/ # 5 numbered .xml files +│ ├── rules-pr-fixer/ # 5 numbered .xml files +│ └── rules-translate/ # 001-general-rules.md + per-locale instructions +├── scripts/ +├── shared-modes/ → symlink to roo-vault/shared-modes/ (vault setup) +├── shared-rules/ → symlink to roo-vault/shared-rules/ (vault setup) +├── shared-skills/ → symlink to roo-vault/shared-skills/ (vault setup) +└── skills/ # project-specific SKILL.md packages + ├── evals-context/SKILL.md + ├── roo-conflict-resolution/SKILL.md + └── roo-translation/SKILL.md +``` + +Note the file `../../../../roo-vault/projects/Roo-Code/.roo/roomotes.yml` (sic — likely `.roomodes` typo) listed in the recursive listing. + +## Setup Scripts + +### `setup-vault.ps1` — the actual vault setup + +The real vault wiring script is **not** at `setup/setup_dev_box.ps1` (that's a separate dev-box bootstrap). It lives at the vault root: [`../../../../roo-vault/setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:1) (Windows; companion `setup-vault.sh` for Linux/macOS). + +Behaviour, per file inspection: + +1. **Argument** — single positional `$ProjectName`; validated against `^[a-zA-Z0-9_-]+$` ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:33)). The project directory is computed as `(parent-of-vault)\`, i.e. sibling to the vault ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:44)). +2. **Detect VS Code Roo settings path** — checks three candidates ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:60-64)): + - `%APPDATA%\Code\User\globalStorage\rooveterinaryinc.roo-cline` + - `%USERPROFILE%\.vscode-server\data\User\globalStorage\rooveterinaryinc.roo-cline` + - `%APPDATA%\Code - Insiders\User\globalStorage\rooveterinaryinc.roo-cline` +3. **Symlink the entire `settings/` directory** under that VS Code path to point at `roo-vault/global-settings/` ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:163-175)). If a real `settings/` exists, it migrates (hash-compares) `mcp_settings.json`, `custom_modes.yaml`, and the legacy `cline_custom_modes.json` into the vault, then renames the original to `settings_backup_` ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:127-154)). +4. **Build per-project `.roo/` blueprint inside the vault** at `roo-vault/projects//.roo/` with subdirs `skills/`, `rules/`, `rules-code/`, `rules-architect/`, `plans/`, `scripts/`, plus a default `{ "mcpServers": {} }` file ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:181-193)). +5. **Symlink `\.roo` → `roo-vault\projects\\.roo`** ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:230-236)). If a real `.roo/` exists, it merges contents non-destructively (no overwrite) and renames the original to `.roo_backup_`. +6. **Symlink `\myplans` → vault's `.roo/plans/`** for stable plan storage across branches ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:246-283)). +7. **Symlink `.roomodes` and `.clinerules`** at the project root if a vault copy exists ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:287-305)). +8. **Symlink shared content** — for each of `shared-modes`, `shared-rules`, `shared-skills`, create a symlink under the project's `.roo/` pointing back at the vault root's directory ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:311-333)). +9. **Update project `.gitignore`** with entries `.roo`, `.roomodes`, `.clinerules`, `myplans` and run `git rm --cached` to untrack any already-committed copies ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:346-375)). +10. **Init git in the vault** itself if needed, with a vault `.gitignore` that excludes `tasks/`, `.cline/`, `*.log`, `.DS_Store`, `.env`, and crucially `global-settings/mcp_settings.json` (because it contains API tokens) ([`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1:380-398)). + +### `setup/setup_dev_box.ps1` — separate dev-box bootstrap + +[`../../../../roo-vault/setup/setup_dev_box.ps1`](../../../../roo-vault/setup/setup_dev_box.ps1:1) is a different script entirely — Windows dev-machine provisioning. It does **not** wire the vault; it installs: + +- **WSL** + AzureLinux 3.0 distro (idempotent, optional drive relocation, `/etc/wsl.conf` systemd enable) ([`setup_dev_box.ps1`](../../../../roo-vault/setup/setup_dev_box.ps1:144-240)). +- **Chocolatey** + tools: Git, VS Code, Python, Docker Desktop, NSSM, GitHub CLI, Azure CLI, Node.js LTS ([`setup_dev_box.ps1`](../../../../roo-vault/setup/setup_dev_box.ps1:266-279)). +- **GitHub CLI extensions** `gh-copilot` and `gh-models` ([`setup_dev_box.ps1`](../../../../roo-vault/setup/setup_dev_box.ps1:307-319)). +- **Azure CLI** `azure-devops` extension ([`setup_dev_box.ps1`](../../../../roo-vault/setup/setup_dev_box.ps1:333-341)). +- **LiteLLM** Python package and a Windows service (`LiteLLMService`) via NSSM, listening on `localhost:4000` ([`setup_dev_box.ps1`](../../../../roo-vault/setup/setup_dev_box.ps1:412-493)) — this is the local OpenAI-compatible proxy that Roo's codebase indexer talks to (see the final banner at [`setup_dev_box.ps1`](../../../../roo-vault/setup/setup_dev_box.ps1:541-556)). +- **VS Code extensions** including `RooVeterinaryInc.roo-cline`, `GitHub.copilot`, plus language tools ([`setup_dev_box.ps1`](../../../../roo-vault/setup/setup_dev_box.ps1:362-380)). +- **Docker + Qdrant** container for the codebase index vector store ([`setup_dev_box.ps1`](../../../../roo-vault/setup/setup_dev_box.ps1:495-535)). + +Implication for the migration plan: the dev-box already has GitHub CLI + `gh-copilot` extension installed and authenticated, which is the foothold Phases 4–5 will build on. + +## Memory / Notes Conventions + +The vault's only "memory" surface beyond Roo's own conventions: + +- [`../../../../roo-vault/plans/`](../../../../roo-vault/plans) — design / audit / decision documents: + - [`api-keys-known-risk.md`](../../../../roo-vault/plans/api-keys-known-risk.md) — accepts the risk of committing free-tier MCP API keys. + - [`orchestrator-rules-audit-2026-04-14.md`](../../../../roo-vault/plans/orchestrator-rules-audit-2026-04-14.md) — running audit of orchestrator delegation rules. + - [`archive/`](../../../../roo-vault/plans/archive) — superseded plans (config audits, mode standardisation). +- Per-project `/projects//.roo/plans/` — symlinked back to `/myplans/` (see step 6 of `setup-vault.ps1`). This is where modes (especially architect) are instructed to drop plan markdown. +- No `memory/`, `notes/`, or `decisions/` top-level folder by name. The vault's collective state lives in `plans/` + per-project `.roo/plans/` + each agent's `update_todo_list` snapshot inside Roo's own globalState. + +## MCP Server Inventory (Vault-wide) + +Compiled from [`../../../../roo-vault/global-settings/mcp_settings.json`](../../../../roo-vault/global-settings/mcp_settings.json:1), [`../../../../roo-vault/projects/Roo-Code/.roo/mcp.json`](../../../../roo-vault/projects/Roo-Code/.roo/mcp.json:1), and the active workspace's [`.roo/mcp.json`](../../../.roo/mcp.json:1) (also vault-managed via the symlink chain). **All token / API-key values are redacted** as `***REDACTED***`. + +| Server name | Scope | Transport | Command / URL | Purpose | Status | +|---|---|---|---|---|---| +| `github` | global | stdio | `docker run -i --rm -e GITHUB_PERSONAL_ACCESS_TOKEN ghcr.io/github/github-mcp-server` (env: `GITHUB_PERSONAL_ACCESS_TOKEN=***REDACTED***`) | GitHub Issues / PRs / repos / commits | Enabled | +| `context7` | global | streamable-http | `https://mcp.context7.com/mcp` (header: `CONTEXT7_API_KEY=***REDACTED***`) | Library-doc lookup (`resolve-library-id`, `query-docs`) | Enabled | +| `tavily` | global | stdio | `docker run -i --rm -e TAVILY_API_KEY mcp/tavily` (env: `TAVILY_API_KEY=***REDACTED***`) | Web search / extract / crawl / map / research | Enabled | +| `microsoft-learn` | global | streamable-http | `https://learn.microsoft.com/api/mcp` (no auth) | Microsoft / Azure docs search and fetch | Enabled | +| `memory` | global | stdio | `npx -y @modelcontextprotocol/server-memory` | Persistent knowledge graph (entities/relations/observations) | **Disabled** in config | +| `filesystem` | global | stdio | `npx -y @modelcontextprotocol/server-filesystem ${WORKSPACE_ROOT}` | Local FS access mirror | **Disabled** | +| `brave-search` | global | stdio | `npx -y @modelcontextprotocol/server-brave-search` (env: `BRAVE_API_KEY=***REDACTED***`) | Web search via Brave | **Disabled** (no API key set) | +| `ado` | per-project (Roo-Code, pgsql-orion) | stdio | `npx -y @azure-devops/mcp msdata` | Azure DevOps repos / pipelines / work items / boards | Enabled | +| `git` | per-project (Roo-Code) | stdio | `docker run --rm -i --mount type=bind,src=c:/git/Roo-Code,dst=/workspace mcp/git --repository /workspace` | Read-write Git over Docker (status, log, diff, commit, branch, …) | Enabled | + +Dual-presence note: the project-level `.roo/mcp.json` for `Roo-Code` and the vault-level `projects/Roo-Code/.roo/mcp.json` are byte-identical because the project copy is a symlink to the vault copy. + +## Cross-links + +- [`00-plan.md`](00-plan.md) · [`10-roo-inventory.md`](10-roo-inventory.md) · [`80-migration-playbook.md`](80-migration-playbook.md) +- Vault home: [`../../../../roo-vault/README.md`](../../../../roo-vault/README.md) diff --git a/docs/investigation/roo-to-copilot/30-squad-inventory.md b/docs/investigation/roo-to-copilot/30-squad-inventory.md new file mode 100644 index 00000000000..2d17d456c58 --- /dev/null +++ b/docs/investigation/roo-to-copilot/30-squad-inventory.md @@ -0,0 +1,214 @@ +--- +phase: 3 +status: complete +owner: architect-subtask +last_updated: 2026-04-26 +sources: + - ../../../../squad/README.md + - ../../../../squad/package.json + - ../../../../squad/packages/squad-cli/package.json + - ../../../../squad/packages/squad-sdk/package.json + - ../../../../squad/.copilot/mcp-config.json + - ../../../../squad/docs/src/content/docs/features/vscode.md + - ../../../../squad/docs/src/content/docs/features/mcp.md + - ../../../../squad/docs/src/content/docs/get-started/choose-your-interface.md + - ../../../../squad/docs/src/content/docs/reference/integration.md + - ../../../../squad/docs/src/content/docs/scenarios/client-compatibility.md + - ../../../../squad/docs/src/content/blog/008-v040-release.md + - ../../../../squad/docs/src/content/blog/018-the-adapter-chronicles.md + - docs/analysis/squad-vs-roo-comparison.md +--- + +# Phase 3 — Squad Inventory + +> Parent plan: [`00-plan.md`](00-plan.md) · Index: [`README.md`](README.md) + +This file answers Q-001 from [`99-open-questions.md`](99-open-questions.md): "What is Squad actually for?". The answer is grounded in `c:/git/squad` (commit state at investigation time) and the existing companion document [`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md), which had already done a deep comparison and is cross-cited liberally. + +## What is Squad? + +Squad is **a CLI-plus-SDK that orchestrates multi-agent "teams" on top of GitHub Copilot**. From [`../../../../squad/README.md`](../../../../squad/README.md:14-22): + +> Squad gives you a human-directed AI development team through GitHub Copilot. Describe what you're building. Get a team of specialists — frontend, backend, tester, lead — that live in your repo as files. They persist across sessions, learn your codebase, share decisions, and help you move faster without giving up oversight. + +Concretely: +- **Distribution:** two npm packages — [`@bradygaster/squad-sdk`](../../../../squad/packages/squad-sdk/package.json:2) and [`@bradygaster/squad-cli`](../../../../squad/packages/squad-cli/package.json:2). Both are at `0.9.1` (alpha; [`README.md`](../../../../squad/README.md:7-10)). +- **Primary entry-point:** the user runs `squad init` to scaffold a `.squad/` directory, then `copilot --agent squad` to run their team in **GitHub Copilot CLI** ([`README.md`](../../../../squad/README.md:54-72)). The interactive shell `squad` is **deprecated** ([`README.md`](../../../../squad/README.md:113), [`README.md`](../../../../squad/README.md:278-284)). +- **State:** committed markdown under `.squad/` — `team.md`, `routing.md`, `decisions.md`, `agents//charter.md`, `agents//history.md`, `skills/`, `log/` ([`README.md`](../../../../squad/README.md:373-396)). +- **Coordinator file:** `.github/agents/squad.agent.md` — the prompt that turns Copilot into the Squad coordinator. It is overwritten by `squad upgrade`; user state in `.squad/` is never touched ([`README.md`](../../../../squad/README.md:88-93)). + +In one line: **Squad is a markdown-based, file-persistent team-of-agents prompt overlay for GitHub Copilot Chat (VS Code) and Copilot CLI**, plus a TypeScript SDK that programs the same orchestration. + +## Repo Layout + +Top-level directory listing of `c:/git/squad`: + +``` +squad/ +├── README.md README.zh.md CHANGELOG.md CONTRIBUTING.md CONTRIBUTORS.md SECURITY.md LICENSE +├── package.json ← npm-workspaces root, 0.9.1 +├── package-lock.json +├── tsconfig.json vitest.config.ts squad.config.ts eslint.config.mjs cspell.json +├── cli.js index.cjs ← bundled CLI entry shims +├── .changeset/ ← independent versioning per package +├── .copilot/ +│ ├── mcp-config.json ← team-shared MCP config (committed) — real file in this repo +│ └── skills/ ← 25 SKILL.md files (collaboration, conduct, CLI wiring, security, …) +├── .github/ ← GitHub workflows (heartbeat, triage, CI, release …) +├── .squad/ ← Squad's own dogfood team state +├── .squad-templates/ ← legacy templates dir +├── docs/ ← Astro-based docs site (features/, get-started/, reference/, scenarios/, blog/) +├── lib/ ← compiled output staging +├── packages/ +│ ├── squad-cli/ ← @bradygaster/squad-cli (the binary) +│ │ ├── package.json +│ │ ├── src/ ← cli/, shell/, commands/, remote-ui/ +│ │ └── templates/ +│ └── squad-sdk/ ← @bradygaster/squad-sdk (the runtime library) +│ ├── package.json +│ ├── src/ ← coordinator/, agents/, casting/, ralph/, runtime/, marketplace/, sharing/, platform/, storage/, streams/, hooks/, tools/, presets/, … +│ └── templates/ +├── samples/ ← 8 sample projects +├── scripts/ ← release/build/sync helpers +├── templates/ ← markdown templates copied into a user's .squad/ on `squad init` +├── test/ test-fixtures/ ← ~200 vitest specs +└── ...lint/style configs (.gitattributes, .lycheeignore, .markdownlint-cli2.jsonc, .npmignore) +``` + +Confirmed via `list_files` on [`../../../../squad`](../../../../squad). Roles: + +- [`packages/squad-sdk/`](../../../../squad/packages/squad-sdk) — the bulk of the codebase. Subsystems include coordinator/fan-out/response-tiers, agents/charter-compiler, casting (persistent agent-name registry), ralph (the watch / triage daemon), runtime (i18n, otel, hooks), marketplace (plugin discovery), sharing (export/import), platform (GitHub vs Azure DevOps detection), storage (fs / in-memory / sql.js providers), streams (sub-squad streams), tools, presets, upstream inheritance. +- [`packages/squad-cli/`](../../../../squad/packages/squad-cli) — the `squad` binary, `bin: { squad: "dist/cli-entry.js" }` ([`packages/squad-cli/package.json`](../../../../squad/packages/squad-cli/package.json:6-8)). Includes an Ink-based `shell/` (deprecated) and `remote-ui/` (Squad RC — a PWA/web companion). +- [`templates/`](../../../../squad/templates), [`packages/squad-sdk/templates/`](../../../../squad/packages/squad-sdk/templates), [`packages/squad-cli/templates/`](../../../../squad/packages/squad-cli/templates) — copies of `squad.agent.md`, `team.md`, `routing.md`, charters, ceremony, skill scaffolds. Multiple copies are kept in sync by [`scripts/sync-templates.mjs`](../../../../squad/scripts/sync-templates.mjs) ([`package.json`](../../../../squad/package.json:11)). +- [`.copilot/mcp-config.json`](../../../../squad/.copilot/mcp-config.json) — **the team-shared MCP config**. The file pattern itself is what Squad recommends to users ([`templates/mcp-config.md`](../../../../squad/templates/mcp-config.md:6-8)). + +## Architecture + +**Type:** A Node CLI binary plus a TypeScript SDK. Not a VS Code extension. Not a chat participant. + +| Dimension | Value | Source | +|---|---|---| +| Runtime | Node `>=22.5.0` | [`../../../../squad/package.json`](../../../../squad/package.json:27) | +| Languages | TypeScript (strict, ESM throughout) | [`../../../../squad/tsconfig.json`](../../../../squad/tsconfig.json), [`../../../../squad/package.json`](../../../../squad/package.json:5) | +| Build | `tsc` per package + esbuild bundle for the CLI | [`../../../../squad/package.json`](../../../../squad/package.json:13) | +| UI runtime | Ink + React 19 (deprecated terminal shell); Squad RC is a PWA | [`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:92) | +| Test | vitest 3 + Playwright | [`../../../../squad/package.json`](../../../../squad/package.json:14-15) | +| Bin | `squad → dist/cli-entry.js` | [`../../../../squad/packages/squad-cli/package.json`](../../../../squad/packages/squad-cli/package.json:6-8) | + +The agent loop is implemented in [`packages/squad-sdk/src/coordinator/`](../../../../squad/packages/squad-sdk/src/coordinator) (coordinator + fan-out + response-tiers) and the long-running watch daemon ("Ralph") in [`packages/squad-sdk/src/ralph/`](../../../../squad/packages/squad-sdk/src/ralph). Cross-referenced by [`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:111-114). + +**Activation surface:** there is no `package.json` `activationEvents` or `contributes` block — Squad is not a VS Code extension. Its VS Code integration relies on **GitHub Copilot Chat reading `.github/agents/squad.agent.md`** as a custom chat-mode-style prompt, plus the existing `.squad/` files as repo-resident memory. See [`docs/src/content/docs/features/vscode.md`](../../../../squad/docs/src/content/docs/features/vscode.md:29-31) and [`docs/src/content/docs/scenarios/remote-qa.md`](../../../../squad/docs/src/content/docs/scenarios/remote-qa.md:18-21). + +## Relationship to GitHub Copilot + +This is **the** core question for Phase 3, and the answer is unambiguous in source: + +### 1. Squad embeds the official GitHub Copilot SDK + +[`packages/squad-sdk/package.json`](../../../../squad/packages/squad-sdk/package.json:235-236): + +```json +"dependencies": { + "@github/copilot-sdk": "^0.1.32", + "vscode-jsonrpc": "^8.2.1" +} +``` + +It does **not** use VS Code's `vscode.lm` API (no such import in the SDK). Instead it links directly to the GitHub Copilot SDK published by GitHub itself (`@github/copilot-sdk`). The wrapper is `SquadClient`, described at [`docs/src/content/docs/reference/integration.md`](../../../../squad/docs/src/content/docs/reference/integration.md:10-12): + +> `SquadClient` wraps `@github/copilot-sdk` with lifecycle management and auto-reconnection. + +The adapter layer that bridges Squad's session interface to the SDK's actual shape is `CopilotSessionAdapter`, documented in [`docs/src/content/docs/whatsnew.md`](../../../../squad/docs/src/content/docs/whatsnew.md:78) and the post-mortem at [`docs/src/content/blog/018-the-adapter-chronicles.md`](../../../../squad/docs/src/content/blog/018-the-adapter-chronicles.md:1-72) (notably — "the Codespaces session exposes `send()`, not `sendMessage()`"). + +### 2. CLI dispatch goes through the Copilot CLI + +For the watch / triage path (Ralph), Squad **shells out to `gh copilot` / `copilot --agent squad`** with a context file via the `-p ` flag ([`README.md`](../../../../squad/README.md:172-178)): + +> Ralph builds a context snapshot … writes this context to a temp file using the `-p ` flag … invokes the agent with that file: `gh copilot -p context.md` … the agent decides which issue to work on. + +The flag `--agent-cmd ` lets the user swap the runner ([`README.md`](../../../../squad/README.md:155-158)). + +### 3. VS Code mode = Copilot Chat reading the `squad.agent.md` agent file + +For VS Code, Squad ships a single markdown file: [`.github/agents/squad.agent.md`](../../../../squad/.github/agents). When opened in VS Code, GitHub Copilot Chat's agent picker discovers this file and exposes it as the **Squad** agent ([`docs/src/content/docs/features/vscode.md`](../../../../squad/docs/src/content/docs/features/vscode.md:29-31)): + +> Creates `.github/agents/squad.agent.md` and `.squad/templates/`. Then open VS Code and select **Squad** from the agent picker. + +This is **not** a custom chat participant in the `vscode.chat.createChatParticipant` sense; Squad does not register a participant. It is a Copilot-Chat–native **agent file** under `.github/agents/`, which Copilot Chat auto-discovers. + +### 4. MCP — Squad does not host an MCP client; it relies on Copilot's + +Per [`templates/mcp-config.md`](../../../../squad/templates/mcp-config.md:6-8): + +> Users configure MCP servers at these locations (checked in priority order): +> 1. **Repository-level:** `.copilot/mcp-config.json` (team-shared, committed to repo) + +The Squad coordinator prompt teaches agents *which MCP tools exist* and *when to call them*. The actual MCP plumbing — server lifecycle, tool dispatch — is performed by **Copilot itself** (CLI or VS Code). This is consistent with [`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:134) ("Squad has only lightweight MCP configuration awareness … Squad does not host the MCP client itself"). The `.copilot/mcp-config.json` filename is the **GitHub-owned convention**; Squad simply documents and uses it. + +### 5. Summary of integration points + +| Squad surface | Talks to Copilot via | File citation | +|---|---|---| +| SDK (`SquadClient`) | `@github/copilot-sdk` (programmatic agent sessions) | [`packages/squad-sdk/package.json`](../../../../squad/packages/squad-sdk/package.json:235), [`docs/src/content/docs/reference/integration.md`](../../../../squad/docs/src/content/docs/reference/integration.md:10-12) | +| `CopilotSessionAdapter` | `@github/copilot-sdk` `CopilotSession` (mapping `sendMessage`/`send`/`on`/`destroy`/`close`) | [`docs/src/content/docs/whatsnew.md`](../../../../squad/docs/src/content/docs/whatsnew.md:78), [`docs/src/content/blog/018-the-adapter-chronicles.md`](../../../../squad/docs/src/content/blog/018-the-adapter-chronicles.md:1) | +| Watch daemon (Ralph) | `gh copilot -p ` (subprocess) | [`README.md`](../../../../squad/README.md:172-178) | +| Interactive use (recommended) | `copilot --agent squad` (Copilot CLI) or VS Code Copilot Chat agent picker | [`README.md`](../../../../squad/README.md:54-72), [`docs/src/content/docs/features/vscode.md`](../../../../squad/docs/src/content/docs/features/vscode.md:29-31) | +| MCP servers | Inherits from Copilot's MCP config (`.copilot/mcp-config.json` and `.vscode/mcp.json`) | [`templates/mcp-config.md`](../../../../squad/templates/mcp-config.md:6-8), [`docs/src/content/docs/features/mcp.md`](../../../../squad/docs/src/content/docs/features/mcp.md:25-28) | + +> ⚠️ **Uncertain:** whether Copilot Chat exposes a per-agent MCP allowlist analogous to Roo's `allowedMcpServers`. Squad's docs imply it inherits *all* configured MCP servers without a Squad-side allowlist mechanism. This becomes a Phase-4/6 question (already tracked as Q-002). + +## Relationship to Roo-Code + +[`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:1-198) already lays this out exhaustively. Highlights: + +- **Not a fork.** Squad is original work by `@bradygaster`. Roo-Code is a fork/derivative of Cline. They share zero code ([`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:25-36)). +- **Conceptual overlap on "modes" / "agents"**, but different mental model: + - Roo modes are **stateless personas** keyed by slug, defined in [`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts:96) and [`schemas/roomodes.json`](../../../schemas/roomodes.json). + - Squad agents are **persistent, named team members** with `charter.md` + evolving `history.md` ([`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:140-142)). They are intended to *learn* across sessions and be committed to git. +- **Tool surface:** Roo has its own native-tool implementations (read_file, apply_diff, write_to_file, execute_command, browser_action, …) executed in-process. Squad's "tools" module is mostly SDK-side primitives (file-write guards, PII scrubbing, reviewer lockout) — execution happens inside the Copilot agent runner ([`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:128-131)). +- **MCP:** Roo is a **first-class MCP client host** with per-mode allowlists ([`docs/design/per-mode-mcp-settings.md`](../../design/per-mode-mcp-settings.md)). Squad is **MCP-aware but not an MCP host**. +- **Provider abstraction:** Roo wraps ~30 LLM providers in [`src/api/providers/`](../../../src/api/providers). Squad has no provider abstraction — model selection is a *policy* (which Copilot-side model tier to ask for) in [`packages/squad-sdk/src/config/models.ts`](../../../../squad/packages/squad-sdk/src/config/models.ts). +- **Parallelism:** Squad runs agents in parallel by default (fan-out, session-pool, `--max-concurrent`, `wave-dispatch`, `fleet-dispatch`); Roo enforces serial sub-task execution ([`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:154-178)). +- **State:** Squad commits team state to git under `.squad/`; Roo persists in VS Code globalState plus shadow-git checkpoints ([`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:144-148)). + +No shared dependencies of note. Both happen to use changesets and vitest. Both use TypeScript. That's the extent of code-level overlap. + +## Feature Overlap Matrix (Roo ↔ Squad) + +| Roo feature (from Phase 1) | Squad has it? | How / where | +|---|---|---| +| Built-in modes (architect / code / ask / debug / orchestrator) | ⚠️ Different model | Squad has *roles* in [`packages/squad-sdk/src/roles/catalog.ts`](../../../../squad/packages/squad-sdk/src/roles/catalog.ts) + persistent named agents from a casting registry. No fixed slugs like Roo's. | +| Custom modes via `.roomodes` / global YAML | ⚠️ Different format | Squad agents are markdown files under `.squad/agents//charter.md` ([`README.md`](../../../../squad/README.md:373-396)). Recently added: `squad.config.ts` SDK-first mode ([`README.md`](../../../../squad/README.md:399-417)). | +| Per-mode tool groups (`read`, `edit`, `command`, `mcp`) | ❌ No | Squad does not expose a tool-group ACL. Tool restrictions are achieved at the prompt level inside the charter, not enforced by the runtime. | +| Per-mode `allowedMcpServers` allowlist | ❌ No | Squad inherits all MCP servers from Copilot's config; no per-agent filter visible in source. | +| Per-mode `fileRegex` edit restriction | ❌ No | Not present in Squad's runtime. Squad's `defineSkill()` and SDK file-write guards exist ([`packages/squad-sdk/src/runtime/`](../../../../squad/packages/squad-sdk/src/runtime)) but are coarser. | +| Orchestrator boomerang (`new_task` → child mode → `attempt_completion`) | ✅ Conceptually | Coordinator dispatches to agents in parallel via `fan-out.ts`; agents return summaries via `attempt_completion`-equivalent. Architecturally different (parallel vs serial). | +| Sub-task isolation / nested condense | ⚠️ Different | Squad uses `.squad/log/` and per-agent `history.md` for persistence; no shadow-git checkpointing. | +| MCP integration (global + per-project + transports) | ⚠️ Inherited | Squad documents `.copilot/mcp-config.json` (CLI) and `.vscode/mcp.json` (VS Code) ([`docs/src/content/docs/features/mcp.md`](../../../../squad/docs/src/content/docs/features/mcp.md:25-28)). The MCP client itself is Copilot's. | +| Custom prompts / rules (`.roo/rules/`, `.roo/rules-/`, `AGENTS.md`) | ⚠️ Different files | Squad uses `.squad/decisions.md`, per-agent `history.md`, plus `.copilot/skills//SKILL.md`. The Anthropic SKILL.md format is shared with Roo's `skills/`. | +| Memory / context features (todo, condense, sliding window) | ⚠️ Different | Squad: `.squad/identity/now.md`, `.squad/identity/wisdom.md`, per-agent `history.md`; "Squad nap" command for compress/prune/archive ([`README.md`](../../../../squad/README.md:117-118)). No automatic context-condensing in the Roo sense (Copilot handles that). | +| Native tools (read_file, apply_diff, write_to_file, execute_command, …) | ❌ Not Squad's responsibility | Tools are whatever Copilot provides. Squad adds SDK-side hooks (file-write guards, reviewer lockout, PII scrubbing). | +| Webview UI (mode picker, MCP toggle, prompts UI) | ❌ N/A | No webview. Optional Squad RC PWA exists but is for chat-style remote control, not config management ([`docs/src/content/docs/features/squad-rc.md`](../../../../squad/docs/src/content/docs/features/squad-rc.md)). | +| Settings storage in VS Code globalStorage | ❌ N/A | Squad state lives in the working tree (`.squad/`), or externalized via `squad externalize` ([`README.md`](../../../../squad/README.md:111)). | +| Parallel agent execution | ✅ Yes | First-class: fan-out, session-pool, `--max-concurrent N`, `wave-dispatch`, `fleet-dispatch` ([`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:160-170)). | +| Watch / autonomous polling daemon | ✅ Yes | Ralph: `squad watch --execute --interval 5` ([`README.md`](../../../../squad/README.md:122-272)). Roo has no equivalent. | +| Localisation (14+ locales) | ❌ Largely English | Squad has runtime i18n module + Chinese README; not the depth of Roo's locale coverage ([`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md:151-152)). | +| Plugin marketplace | ✅ Yes | `squad plugin marketplace add/remove/list/browse` ([`README.md`](../../../../squad/README.md:115)); upstream Squad sources via `squad upstream`. | + +## Preliminary Verdict (final verdict reserved for Phase 7) + +> ⚠️ This is a Phase-3-only assessment based on local source inspection. Phases 4–7 may revise it. + +- **When Squad helps:** When the user actually wants the *team-of-personas / parallel-execution / autonomous-watch-loop* paradigm. Squad shines for `squad watch --execute` overnight triage, GitHub-issue→PR pipelines, and parallel fan-out across many independent files. It's also useful as a packaged "best practices for the `.copilot/mcp-config.json` + `.github/agents/squad.agent.md` + `.squad/` pattern" — i.e., it codifies a Copilot-native repo layout the user could otherwise hand-craft. +- **When Squad is redundant:** For the user's *core* Roo workflow — single-developer interactive coding with strongly typed mode definitions, per-mode `allowedMcpServers`, edit-file regex restrictions — Squad does not improve on what raw Copilot Chat custom modes + `.github/copilot-instructions.md` would give them. Squad does not provide tool-group ACLs, per-agent MCP allowlists, or `fileRegex` edit gates. Going through Squad on top of Copilot adds a markdown-prompt layer without buying back those Roo guardrails. +- **When Squad adds risk:** + 1. **Alpha software** (`0.9.1`, "Status: alpha"; [`README.md`](../../../../squad/README.md:7-10)). Recent post-mortems ([`docs/src/content/blog/018-the-adapter-chronicles.md`](../../../../squad/docs/src/content/blog/018-the-adapter-chronicles.md), [`docs/src/content/blog/024-v0823-release.md`](../../../../squad/docs/src/content/blog/024-v0823-release.md)) describe P0 Codespaces breakage and ESM-import crashes patched recently — the integration surface against `@github/copilot-sdk` is not yet stable. + 2. **Indirection.** A bug now has three potential layers: Squad coordinator prompt, `@github/copilot-sdk` adapter, Copilot itself. Diagnosis cost rises. + 3. **Different mental model from Roo.** Squad agents are *persistent named team members* expected to evolve `history.md`. Roo modes are *stateless slugs*. Migrating from one to the other is not a rename — it's an ontology shift that may not match the user's working style. The user already maintains a `roo-vault` with global modes that explicitly avoid persistent per-agent learning state; Squad's model fights that. + 4. **No per-mode MCP allowlist.** This is one of the user's documented Roo guardrails (see Phase 1's per-mode MCP section and [`.roomodes`](../../../.roomodes:179-181) which sets `allowedMcpServers: [github, git]` on `docs-extractor`, etc.). Squad does not preserve this. + +## Cross-links + +- [`00-plan.md`](00-plan.md) · [`10-roo-inventory.md`](10-roo-inventory.md) · [`60-gap-analysis.md`](60-gap-analysis.md) · [`70-migration-paths.md`](70-migration-paths.md) +- Companion: [`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md) +- Squad home: [`../../../../squad/README.md`](../../../../squad/README.md) diff --git a/docs/investigation/roo-to-copilot/40-copilot-chat-research.md b/docs/investigation/roo-to-copilot/40-copilot-chat-research.md new file mode 100644 index 00000000000..86d92cd0512 --- /dev/null +++ b/docs/investigation/roo-to-copilot/40-copilot-chat-research.md @@ -0,0 +1,1302 @@ +--- +phase: 4 +status: complete +owner: architect-subtask +last_updated: 2026-04-26 +sources: + - https://code.visualstudio.com/docs/copilot/customization/custom-chat-modes + - https://code.visualstudio.com/docs/copilot/customization/custom-instructions + - https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions + - https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions + - https://github.com/microsoft/vscode/issues/305642 + - https://github.com/microsoft/vscode/issues/272199 + - https://code.visualstudio.com/docs/copilot/customization/prompt-files + - https://docs.github.com/en/copilot/tutorials/customization-library/prompt-files + - https://github.com/microsoft/vscode-copilot-release/issues/12853 + - https://learn.microsoft.com/visualstudio/ide/copilot-chat-context + - https://code.visualstudio.com/docs/copilot/agents/agent-tools + - https://code.visualstudio.com/docs/copilot/concepts/tools + - https://github.com/microsoft/vscode/issues/251603 + - https://github.com/microsoft/vscode/issues/251515 + - https://github.com/microsoft/vscode-copilot-release/issues/13065 + - https://github.com/orgs/community/discussions/167721 + - https://code.visualstudio.com/docs/copilot/customization/mcp-servers + - https://code.visualstudio.com/docs/copilot/reference/mcp-configuration + - https://code.visualstudio.com/api/extension-guides/ai/mcp + - https://docs.github.com/en/copilot/customizing-copilot/extending-copilot-chat-with-mcp + - https://code.visualstudio.com/docs/configure/settings-sync + - https://code.visualstudio.com/docs/configure/profiles + - https://code.visualstudio.com/docs/copilot/agents/agent-tools + - https://github.com/modelcontextprotocol/servers/issues/3460 + - https://github.com/microsoft/vscode/issues/253039 + - https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode + - https://code.visualstudio.com/docs/copilot/agents/overview + - https://code.visualstudio.com/docs/copilot/agents/subagents + - https://code.visualstudio.com/docs/copilot/customization/custom-agents + - https://code.visualstudio.com/docs/copilot/customization/agent-plugins + - https://code.visualstudio.com/docs/copilot/chat/chat-checkpoints + - https://code.visualstudio.com/docs/copilot/reference/copilot-settings + - https://code.visualstudio.com/docs/copilot/reference/copilot-vscode-features + - https://code.visualstudio.com/api/extension-guides/chat + - https://code.visualstudio.com/api/extension-guides/ai/chat + - https://code.visualstudio.com/api/extension-guides/tools + - https://code.visualstudio.com/api/extension-guides/ai/tools + - https://code.visualstudio.com/api/references/vscode-api#chat + - https://code.visualstudio.com/blogs/2026/02/05/multi-agent-development + - https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode + - https://github.com/microsoft/vscode-extension-samples/tree/main/chat-sample + - https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents +--- + + + +# Phase 4 — GitHub Copilot Chat (VS Code) Research + +> Parent plan: [`00-plan.md`](00-plan.md) · Index: [`README.md`](README.md) + +**What this file is for:** Capture, with citations, every Copilot Chat capability relevant to replacing Roo. Each section MUST start with a `Sources` subsection listing official docs URLs and access dates. + +## Official Documentation Links + +### Sources +> *What goes here:* Curated list of canonical URLs (Microsoft Learn, GitHub Docs, code.visualstudio.com) covering Copilot Chat overall, with access dates. + +> *What goes here:* Brief annotated list of which doc page covers which topic. + +## Custom Chat Modes (`.chatmode.md`) + +### Sources + +- [`custom-chat-modes`](https://code.visualstudio.com/docs/copilot/customization/custom-chat-modes) — VS Code "Custom agents in VS Code" doc (the URL still says `custom-chat-modes`; the page title and content have been renamed to **Custom agents** and the file extension to **`.agent.md`**). Accessed 2026-04-26. +- [`vscode/issues/305642`](https://github.com/microsoft/vscode/issues/305642) — community / maintainer thread documenting that the only user-data folder that picks up agents/instructions/prompts is `%APPDATA%\Code\User\prompts` (i.e. outside the profile-scoped folders). Accessed 2026-04-26. +- [`orgs/community/discussions/175649`](https://github.com/orgs/community/discussions/175649) — community thread re-stating that AGENTS.md support in VS Code is currently experimental / off by default. Accessed 2026-04-26. + +### Findings (2026-04-26) + +> ⚠️ **Naming change resolves Q-004 partially and supersedes the task brief.** As of the current docs, what Roo-Code's brief still calls "`.chatmode.md`" has been **renamed to `.agent.md`** ("Custom agents") in VS Code. The page explicitly states: +> +> > "Custom agents were previously known as custom chat modes. The functionality remains the same, but the terminology has been updated… If you have existing `.chatmode.md` files, rename them to `.agent.md`…" +> +> All findings below use the **current** name; treat any user docs that say `.chatmode.md` as legacy. + +#### 1. File format & frontmatter schema + +Custom agents are Markdown files with the **`.agent.md`** extension and an optional YAML frontmatter header. The fully-documented frontmatter fields are: + +| Field | Purpose | +|---|---| +| `description` | Placeholder text for the chat input | +| `name` | Display name (defaults to filename) | +| `argument-hint` | Hint text in the chat input | +| `tools` | Array of tool / tool-set / MCP-tool names available to this agent. `mcpserver/*` allows all tools of one MCP server. | +| `agents` | Array of agent names allowed as **subagents** (`*` = all, `[]` = none) | +| `model` | Single model name **or** prioritized array — first available wins | +| `user-invocable` | Boolean; if `false`, only callable as a subagent | +| `disable-model-invocation` | Boolean; if `true`, can't be invoked as a subagent | +| `target` | `vscode` or `github-copilot` | +| `mcp-servers` | Inline MCP server JSON (only when `target: github-copilot`) | +| `handoffs` | List of `{label, agent, prompt, send, model}` for sequential workflow buttons | +| `hooks` (Preview) | Per-agent `PreToolUse` / `PostToolUse` shell hooks | +| `infer` | Deprecated — replaced by `user-invocable` + `disable-model-invocation` | + +Quote (canonical schema row for `tools`): + +> "A list of tool or tool set names that are available for this custom agent. Can include built-in tools, tool sets, MCP tools, or tools contributed by extensions. To include all tools of an MCP server, use the `/*` format." + +The body is Markdown and is "prepended to the user chat prompt" when the agent is selected. **Note:** the `.chatmode.md` schema fields originally documented (`description`, `tools`, `model`) are a **strict subset** of the current schema — no fields were removed, only added. + +VS Code also natively reads **Claude `.md` agent files** in `.claude/agents` with comma-separated `tools` / `disallowedTools` strings: + +> "VS Code maps Claude-specific tool names to the corresponding VS Code tools. Both the VS Code `.agent.md` format (with YAML arrays for tools) and the Claude format (with comma-separated strings) are supported." + +#### 2. Workspace location + +Default workspace folder is **`.github/agents/`** (formerly `.github/chatmodes/`). VS Code also auto-detects `.md` files in `.claude/agents/` (Claude format). + +> "Workspace | `.github/agents` folder +> Workspace (Claude format) | `.claude/agents` folder" + +Additional workspace locations are configurable via the `chat.agentFilesLocations` setting. Monorepo / parent-repo discovery is gated by `chat.useCustomizationsInParentRepositories`. + +#### 3. User-profile location on Windows + +The doc lists user-scope as `~/.copilot/agents` **or** "your user data (specific to your VS Code profile)". On Windows 11 that resolves to: + +- `%USERPROFILE%\.copilot\agents\` — the cross-tool location shared with Copilot CLI, **and** +- `%APPDATA%\Code\User\prompts\` — the historical profile-scoped folder. ⚠️ Per [`microsoft/vscode#305642`](https://github.com/microsoft/vscode/issues/305642) (accessed 2026-04-26): +> +> > "Currently, the only user data folder that picks up agents, instructions or prompts is `%APPDATA%\Code\User\prompts` (i.e. outside the profile)…" + +So on Windows the practical paths are `C:\Users\\.copilot\agents\` and `C:\Users\\AppData\Roaming\Code\User\prompts\`. **Resolves Q-004** for chatmodes (workspace = `.github/agents/`, user = `%APPDATA%\Code\User\prompts\` and/or `%USERPROFILE%\.copilot\agents\`). + +⚠️ uncertain — the doc says "or your user data (specific to your VS Code profile)" but [`microsoft/vscode#305642`](https://github.com/microsoft/vscode/issues/305642) suggests that profile-scoped user-data folders are **not** actually scanned today; only the global `prompts/` folder is. Filed as Q-015. + +#### 4. Invocation + +Custom agents appear in the **agents dropdown** in the Chat view (next to the chat input). The user picks one and the rest of the conversation runs under that agent's persona, tool list, and model choice. Helpers: + +- `/agents` in the chat input opens the **Configure Custom Agents** menu. +- `/create-agent` generates a new agent file via AI. +- After a response, **handoff buttons** can switch to a target agent with a pre-filled (and optionally auto-sent) prompt. + +There is **no `/` slash-command invocation** the way Roo's commands work — selection is via dropdown or handoff button, not slash command. + +#### 5. Critical comparison to Roo + +| Roo capability | Copilot custom agent equivalent | Verdict | +|---|---|---| +| (a) Restrict edits to specific file globs (Roo `fileRegex` per group, e.g. architect mode = `\.md$`) | The frontmatter has **no `fileRegex` / `applyTo` field**. The only way to influence what files an agent touches is to instruct it in prose in the body, or to omit the `edit` tool entirely (which blocks **all** edits, not just unwanted ones). | **No** (no equivalent). ⚠️ Resolves part of Q-005 (lossy mapping). | +| (b) Restrict which tools / MCP servers it may call | **Yes.** The `tools` array is an explicit allowlist; built-in tools, tool sets, extension tools, and MCP tools (including `mcpserver/*` whole-server grants) are all selectable. Per the doc: *"If a given tool is not available when using the custom agent, it is ignored."* This is the closest analogue to Roo's per-mode `allowedMcpServers` / `groups`. | **Yes** (and stronger than Roo for non-MCP tools). **Resolves Q-002 — yes**, Copilot Chat supports per-agent tool/MCP allowlists, including a wildcard `serverName/*` form. | +| (c) Auto-launch sub-agents (Roo Orchestrator's `new_task` boomerang) | The frontmatter `agents:` field plus the built-in `agent` tool let an agent invoke other agents as **subagents**. The doc shows a Feature-Builder → Researcher → Implementer example. | **Partial / yes.** Sub-agent dispatch exists and is officially documented (no longer experimental for the basic case; "nested subagents" still flagged experimental). **Resolves Q-003 — yes** (with caveats). Roo's "boomerang return-to-orchestrator with summary" pattern is approximated by handoffs + the `agent` tool but is not a 1:1 protocol; needs Phase 4d follow-up. | + +Quote supporting the tool-allowlist verdict: + +> "A planning agent might only need read-only tools for research and analysis to prevent accidental code changes, while an implementation agent would need full editing capabilities. Custom agents let you specify exactly which tools are available for each task…" + +#### 6. Versioning / recent changes + +- The feature first shipped as "Custom chat modes" with `.chatmode.md` files in the **VS Code 1.101 (June 2025)** Copilot Chat release. +- Renamed to "Custom agents" with `.agent.md` files and `.github/agents/` location in a 2025-Q4 / 2026-Q1 release; legacy `.chatmode.md` files in the old `.github/chatmodes/` folder are still loaded but the docs instruct users to rename. +- Subagents, handoffs, scoped hooks, Claude `.claude/agents/` interop, and organization-level agents (`github.copilot.chat.organizationCustomAgents.enabled`) are all post-rename additions. + +⚠️ uncertain — exact version numbers for the rename and for subagent GA. Filed as Q-016. + +## Custom Instructions (`.github/copilot-instructions.md`) + +### Sources + +- [`custom-instructions`](https://code.visualstudio.com/docs/copilot/customization/custom-instructions) — VS Code "Use custom instructions in VS Code". Accessed 2026-04-26. +- [`docs.github.com .../add-repository-instructions`](https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions) — GitHub-side companion doc covering `.github/copilot-instructions.md`, `.github/instructions/*.instructions.md`, and `AGENTS.md`. Accessed 2026-04-26. +- [`docs.github.com .../add-repository-instructions` (alt path)](https://docs.github.com/en/copilot/how-tos/copilot-on-github/customize-copilot/add-custom-instructions/add-repository-instructions) — same content, customize-copilot URL tree. Accessed 2026-04-26. +- [`microsoft/vscode#272199`](https://github.com/microsoft/vscode/issues/272199) — confirms user-instruction storage path on Windows is `%APPDATA%\Code\User\prompts\`. Accessed 2026-04-26. + +### Findings (2026-04-26) + +#### 1. Repo-level `.github/copilot-instructions.md` + +- **Location:** exactly `.github/copilot-instructions.md` at the workspace root. VS Code auto-detects it. +- **When applied:** automatically prepended/attached to **every chat request** in the workspace (Chat view + agent mode + inline chat that goes through Chat). Per the doc: + > "VS Code automatically detects a `.github/copilot-instructions.md` Markdown file in the root of your workspace and applies the instructions in this file to all chat requests within this workspace." +- **Not applied to** code-completion-style **inline suggestions** (the ghost-text completer): + > "Custom instructions are not taken into account for inline suggestions as you type in the editor." +- **Size limits:** no hard byte/token limit is documented in the VS Code page. The GitHub-side prompt-template for cloud agent says *"Instructions must be no longer than 2 pages"* — that's a **soft style guideline**, not an enforced cap. ⚠️ uncertain — exact token cap. Filed as Q-017. +- **Precedence:** see precedence model below; repo-level is mid-tier (Personal > Repository > Organization). + +#### 2. Path-scoped `.github/instructions/*.instructions.md` with `applyTo` + +**Supported.** Schema (frontmatter): + +| Field | Required | Description | +|---|---|---| +| `name` | No | Display name (defaults to filename) | +| `description` | No | Hover description in Chat view | +| `applyTo` | No | Comma-separated glob(s) relative to workspace root. `**` = all files. If omitted, the file is **not** applied automatically; it can only be attached manually. | + +GitHub also documents an `excludeAgent: "code-review" | "cloud-agent"` flag on the GitHub-side processing, used to opt the file out of code-review or cloud-agent runs. + +Quote on auto-application: + +> "The agent determines which instructions files to apply based on the file patterns specified in the `applyTo` property in the instructions file header or semantic matching of the instruction description to the current task." + +Workspace location is `.github/instructions/` (recursively scanned); additional locations configurable via `chat.instructionsFilesLocations`. User-scope locations: `~/.copilot/instructions`, `~/.claude/rules`, and the `instructions` folder of the current VS Code profile. + +> ⚠️ **GitHub-side caveat (separate from VS Code):** the GitHub.com docs state *"Currently, on GitHub.com, path-specific custom instructions are only supported for Copilot cloud agent and Copilot code review."* — meaning a `.instructions.md` file influences cloud-agent / code-review on GitHub but **not** every Copilot surface server-side, although VS Code Copilot Chat **does** honor it locally. + +**Precedence vs the repo-level file:** the VS Code doc says all instruction files are merged with **no specific order guaranteed within a tier**; the GitHub doc says *"If the path you specify matches a file that Copilot is working on, and a repository-wide custom instructions file also exists, then the instructions from both files are used"* (additive, not override). + +#### 3. User / personal instructions via VS Code settings + +The settings-based instruction keys are **deprecated for code generation and test generation as of VS Code 1.102** in favor of file-based instructions. The remaining (still-supported) keys are: + +| Scenario | Setting key | +|---|---| +| Code review | `github.copilot.chat.reviewSelection.instructions` | +| Commit messages | `github.copilot.chat.commitMessageGeneration.instructions` | +| Pull request descriptions | `github.copilot.chat.pullRequestDescriptionGeneration.instructions` | + +**Deprecated** (still recognized but flagged): + +- `github.copilot.chat.codeGeneration.instructions` +- `github.copilot.chat.testGeneration.instructions` + +Each accepts an array of `{text}` or `{file}` entries. + +**Storage on Windows:** these settings live in the VS Code user `settings.json`, which on Windows is `%APPDATA%\Code\User\settings.json`. User-scope **instruction files** themselves go into `%APPDATA%\Code\User\prompts\` (per [`vscode#272199`](https://github.com/microsoft/vscode/issues/272199): *"`%APPDATA%\Code\User\prompts\` it is on Windows"*) and/or `%USERPROFILE%\.copilot\instructions\`. **Resolves Q-004** for instructions. + +Settings Sync can sync user-scope instruction files across devices via the **"Prompts and Instructions"** sync category. + +#### 4. AGENTS.md support — native? + +**Yes — natively supported in both VS Code Copilot Chat and on GitHub.com.** The VS Code page lists `AGENTS.md` as an "always-on" instruction source: + +> "VS Code automatically detects an `AGENTS.md` Markdown file in the root of your workspace and applies the instructions in this file to all chat requests within this workspace." + +Toggled by the `chat.useAgentsMdFile` setting (default **on** in current builds). Nested per-folder `AGENTS.md` files are gated by the experimental `chat.useNestedAgentsMdFiles` setting. + +The GitHub-side doc adds: + +> "You can create one or more `AGENTS.md` files, stored anywhere within the repository. When Copilot is working, the nearest `AGENTS.md` file in the directory tree will take precedence." + +VS Code also natively reads `CLAUDE.md` (root, `.claude/CLAUDE.md`, `~/.claude/CLAUDE.md`, `CLAUDE.local.md`) under `chat.useClaudeMdFile`, and `GEMINI.md` server-side per the GitHub doc. + +⚠️ uncertain — older community thread [`#175649`](https://github.com/orgs/community/discussions/175649) (mid-2025) said AGENTS.md was "experimental and off by default". The current VS Code doc treats it as a first-class always-on source, suggesting the default flipped to **on** between mid-2025 and the 2026-04-26 doc snapshot. Exact release version is filed as Q-016. + +#### 5. Comparison to Roo — precedence model side-by-side + +**Copilot precedence (high → low) as documented:** + +1. **Personal** instructions (user-level: `%APPDATA%\Code\User\prompts\` files, `~/.copilot/instructions/`, `~/.claude/rules/`, settings-based deprecated keys) — *highest* +2. **Repository** instructions (`.github/copilot-instructions.md` + matching `.github/instructions/*.instructions.md` + nearest `AGENTS.md` + `CLAUDE.md`) +3. **Organization** instructions (delivered via `github.copilot.chat.organizationInstructions.enabled`) — *lowest* + +> "Higher-priority instructions take precedence when conflicts occur: +> 1. Personal instructions (user-level, highest priority) +> 2. Repository instructions (`.github/copilot-instructions.md` or `AGENTS.md`) +> 3. Organization instructions (lowest priority)" + +Within a tier, no order is guaranteed; all matching files are concatenated into context. + +**Roo precedence (high → low) per [`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts):** + +1. Mode `customInstructions` field (highest, hard-coded into system prompt) +2. Project `.roo/rules-/` files +3. Project `.roo/rules/` files + nearest `AGENTS.md` +4. Global `~/.roo/rules-/` and `~/.roo/rules/` +5. Global `customInstructions` setting + +**Mapping table:** + +| Roo concept | Closest Copilot equivalent | Notes / loss | +|---|---|---| +| `.roomodes` / `custom_modes.yaml` (mode definitions) | `.github/agents/.agent.md` (workspace) + `%APPDATA%\Code\User\prompts\.agent.md` (user) | Frontmatter is similar shape; `groups`/`fileRegex` does not survive (see (a) above). | +| Mode `roleDefinition` | `.agent.md` body (Markdown) | 1:1. | +| Mode `whenToUse` | `description` frontmatter field (loose) | Copilot has no formal "when to auto-pick this mode" field; description hints only. | +| Mode `customInstructions` | Body text **plus** linked `.instructions.md` files | Copilot has no per-mode `customInstructions` slot; you compose via Markdown links. | +| Mode `groups` (tool-group allowlist) | `.agent.md` `tools:` array | Copilot is **finer-grained** (per individual tool, not group). | +| Mode `allowedMcpServers` | `.agent.md` `tools:` entries with `serverName/*` wildcard | **Direct equivalent.** Resolves Q-002. | +| Mode `fileRegex` per group | *(none)* | **No equivalent**; lossy. Must be enforced via prose instructions. | +| Project `.roo/rules/*.md` | `.github/copilot-instructions.md` (single) **or** `.github/instructions/*.instructions.md` with `applyTo: "**"` | Multi-file Roo rules collapse cleanly into the `.instructions.md` directory. | +| Project `.roo/rules-/*.md` | `.agent.md` body + linked `.instructions.md` files referenced from that one agent | **No first-class per-mode rules folder.** The "scope by agent" concept doesn't exist in instructions; you have to either inline into the agent body or use a naming convention. ⚠️ Filed as Q-018. | +| Global `~/.roo/rules/*.md` | `%APPDATA%\Code\User\prompts\*.instructions.md` and/or `~/.copilot/instructions/*.instructions.md` | Direct equivalent. | +| `AGENTS.md` (project root) | `AGENTS.md` (project root) — **natively read** | 1:1. | + +#### Roo open questions resolved by this section + +- **Q-002** (per-mode MCP allowlists in Copilot Chat) — **YES**, via `tools: ['mcpserver/*']` in `.agent.md` frontmatter. +- **Q-003** (sub-agent / orchestrator parity) — **YES (partial)**, via the `agent` tool plus the `agents:` frontmatter allowlist; subagents are documented and supported, with handoffs as the analogue to boomerang return. +- **Q-004** (custom chatmodes on disk on Windows) — **RESOLVED**: workspace = `.github/agents/`, user = `%APPDATA%\Code\User\prompts\` and/or `%USERPROFILE%\.copilot\agents\`. +- **Q-005** (auto-conversion of `.roomodes` schema) — **partially resolved**: a mechanical converter is feasible for `slug → filename`, `name → name`, `roleDefinition → body`, `customInstructions → body`, `allowedMcpServers → tools[]`. Lossy fields: `fileRegex` (no equivalent), `whenToUse` (description only), `groups` (must expand to individual tool list). Full converter spec belongs in Phase 8. + +## Prompt Files (`.prompt.md`) + +### Sources + +- [`prompt-files`](https://code.visualstudio.com/docs/copilot/customization/prompt-files) — VS Code "Use prompt files in VS Code". Accessed 2026-04-26. +- [`docs.github.com — Prompt files`](https://docs.github.com/en/copilot/tutorials/customization-library/prompt-files) — GitHub-side prompt-files index (preview status, IDE availability). Accessed 2026-04-26. +- [`custom-chat-modes#tool-list-priority`](https://code.visualstudio.com/docs/copilot/customization/custom-chat-modes#_tool-list-priority) — precedence between prompt-file `tools` and referenced agent's `tools`. Accessed 2026-04-26. +- [`vscode-copilot-release/issues/12853`](https://github.com/microsoft/vscode-copilot-release/issues/12853) — confirms `%APPDATA%\Code\User\prompts\` is shared by `.instructions.md`, `.prompt.md`, and tool sets on Windows. Accessed 2026-04-26. + +### Findings (2026-04-26) + +#### 1. File format & frontmatter schema + +Prompt files are Markdown documents with the **`.prompt.md`** extension and an optional YAML frontmatter header. Per the VS Code doc: + +> "Fill in the YAML frontmatter at the top of the file to configure the prompt's description, agent, tools, and other settings." + +Schema (all fields optional): + +| Field | Description | +|---|---| +| `description` | Short description of the prompt. | +| `name` | Slash-command name shown after typing `/` in chat. Defaults to the filename. | +| `argument-hint` | Hint text shown in the chat input field to guide users. | +| `agent` | Built-in agent (`ask`, `agent`, `plan`) **or** the name of a custom agent. Defaults to the currently selected agent. If `tools` is specified, the default becomes `agent`. | +| `model` | Language model to use; defaults to the currently-selected model. | +| `tools` | Array of tool / tool-set / MCP-tool names available while the prompt runs (same shape as `tools` in `.agent.md`). | + +> ⚠️ **Naming-rename status:** Unlike chat modes (`.chatmode.md` → `.agent.md`), prompt files have **not** been renamed — the extension is still `.prompt.md` and the frontmatter field for selecting the agent is `agent` (not `mode`). Older blog posts that show `mode: ask|edit|agent` describe a deprecated alias; current docs use `agent`. + +#### 2. Workspace location + +> "| Scope | Default file location | +> | Workspace | `.github/prompts` folder | +> | User profile | Your user data (specific to your VS Code profile) |" + +Additional workspace folders are configurable via the `chat.promptFilesLocations` setting. There is **no `.claude/prompts/`** auto-discovery analogue — Claude format is supported only for agents and rules, not prompts. + +#### 3. User-profile location on Windows + +The VS Code page says only "your user data (specific to your VS Code profile)". GitHub issue [`vscode-copilot-release#12853`](https://github.com/microsoft/vscode-copilot-release/issues/12853) is explicit: + +> "It's `AppData\Roaming\Code - Insiders\User\prompts` is the default for Windows and used for both prompts and instructions." + +For VS Code Stable the equivalent is **`%APPDATA%\Code\User\prompts\`** (the same folder already documented in [`microsoft/vscode#272199`](https://github.com/microsoft/vscode/issues/272199) for `.instructions.md`). **Confirmed: `.prompt.md`, `.instructions.md`, `.agent.md` (per Q-015), and `*.toolsets.jsonc` (see Tool Sets §3 below) all share `%APPDATA%\Code\User\prompts\` on Windows.** **Resolves Q-004** for prompt files. + +#### 4. Invocation + +> "You have multiple options to run a prompt file: +> - In the Chat view, type `/` followed by the prompt name in the chat input field. Agent skills also appear as slash commands alongside prompt files. +> - Run the **Chat: Run Prompt** command from the Command Palette (⇧⌘P) and select a prompt file from the Quick Pick. +> - Open the prompt file in the editor, and press the play button in the editor title area." + +The slash command is the prompt's `name` (or filename). There is **no documented keybinding** for a specific prompt; binding would have to go through `Chat: Run Prompt` plus a `keybindings.json` `args` entry. ⚠️ uncertain whether `keybindings.json` accepts a prompt-name argument. Filed as **Q-019**. + +#### 5. Parameterization + +Two officially-documented mechanisms: + +1. **Free-form arguments after the slash command:** + > "You can add extra information in the chat input field. For example, `/create-react-form formName=MyForm` or `/create-api for listing customers`." + + These extra tokens are appended to the prompt body as part of the user message — they are **not** typed parameters; the prompt body is responsible for parsing them in prose. + +2. **Tool references inside the body** via `#tool:`: + > "To reference agent tools in the body text, use the `#tool:` syntax. For example, to reference the `browser` tool, use `#tool:browser`." + +3. **References to other workspace files (including other prompt files)** via Markdown links: + > "You can reference other workspace files by using Markdown links… You can even reference other prompt files for shared instructions." ([Microsoft Learn — *Customize chat responses and set context*](https://learn.microsoft.com/visualstudio/ide/copilot-chat-context?view=visualstudio#use-prompt-files)) + + This is the closest thing to **prompt chaining**: a prompt can pull in another prompt's body by linking to it. There is **no documented `${input:name}` / `${selection}` / `${file}` / `${workspaceFolder}` substitution syntax** in the VS Code prompt-files page (those are `tasks.json` / `launch.json` variables per the [Variables reference](https://code.visualstudio.com/docs/reference/variables-reference)). ⚠️ uncertain — community blog posts occasionally show `${input:name}` working, but the current VS Code prompt-files doc does not document it. Filed as **Q-020**. + +#### 6. Interaction with custom agents + +A prompt **can specify which agent it runs under** via the `agent` frontmatter field (built-in `ask`/`agent`/`plan`, or the name of a `.agent.md` custom agent). When both the prompt and the referenced agent declare `tools`, the VS Code custom-agents doc states the precedence is: + +> "Tools specified in the prompt file (if any). Tools from the referenced custom agent in the prompt file (if any)." + +That is, **prompt-file `tools` win over the agent's `tools`**, which is the opposite of what one might assume. This matters when designing a "scoped" prompt that should run under a tightly-restricted agent — declaring `tools:` on the prompt **widens** the allowlist beyond what the agent permits. + +Conversely, **agents can embed prompts** only indirectly: an agent body can Markdown-link to a prompt file, but there is no `prompts:` frontmatter array on agents. Sub-prompt invocation must go through the user-visible slash command or via the `agent` tool dispatching to another agent that runs a prompt. + +> "Agents, prompt files, or skills? Use custom agents when you need a persistent persona with specific tool restrictions, model preferences, or handoffs between roles. For one-off tasks that don't need tool restrictions, use prompt files." + +#### 7. Comparison to Roo + +| Roo concept | Closest Copilot prompt-file equivalent | Verdict | +|---|---|---| +| Mode selection (`/architect`, `/code` slash) | `.prompt.md` slash command (`/`) — but binds to a prompt, not a persistent persona | **Different abstraction.** Roo modes persist for the conversation; Copilot prompts execute one turn. The persistent analogue is `.agent.md` (Phase 4a). | +| Roo `customInstructions` per mode | Prompt body (Markdown) | 1:1 for one-shot tasks; for persistent persona use `.agent.md`. | +| Orchestrator dispatching `new_task` with a templated message | A prompt file invoked via `/promptname args…`, **or** the same prompt invoked from inside an agent that uses the `agent` tool | **Partial.** No first-class "templated subtask" object; closest is "prompt body + free-form args + Markdown-linked sub-prompts". | +| Template variables (Roo doesn't really have these either; mentions are via `@` references) | Prompt body uses Markdown links to files and `#tool:` for tools; no documented `${input:name}` substitution | ⚠️ Q-020. | +| Reusable mode + reusable rule file separately | Prompt-file `agent:` frontmatter + body Markdown-link to instruction files | Cleaner separation of concerns than Roo. | + +**Headline:** prompt files are **largely additive** capability over Roo — Roo has no first-class equivalent. They occupy the niche of "named, reusable, parameterizable one-shot user message" that Roo only approximates by either (a) typing a long message into the chat or (b) pre-seeding a subtask via the Orchestrator. + +#### 8. Limits / known gaps + +- **Public preview status.** The GitHub doc explicitly notes: *"Copilot prompt files are in public preview and subject to change. Prompt files are only available in VS Code, Visual Studio, and JetBrains IDEs."* — meaning prompt files are **not** picked up by Copilot CLI or by the GitHub.com cloud agent. Affects Phase 5 (CLI) directly. +- **No typed argument schema.** Args are free-text appended to the body; the prompt has to parse them. ⚠️ Q-020 (variable substitution). +- **No documented prompt-file size cap.** Prompts share the single chat-request token budget with instructions and the user message; large prompts compete with instruction-file context. + +## MCP Support + +### Sources + +- [`docs/copilot/customization/mcp-servers`](https://code.visualstudio.com/docs/copilot/customization/mcp-servers) — VS Code "Add and manage MCP servers in VS Code". Accessed 2026-04-26. +- [`docs/copilot/reference/mcp-configuration`](https://code.visualstudio.com/docs/copilot/reference/mcp-configuration) — VS Code "MCP configuration reference" (canonical schema). Accessed 2026-04-26. +- [`api/extension-guides/ai/mcp`](https://code.visualstudio.com/api/extension-guides/ai/mcp) — VS Code "MCP developer guide". Accessed 2026-04-26. +- [`docs.github.com — Extending Copilot Chat with MCP`](https://docs.github.com/en/copilot/customizing-copilot/extending-copilot-chat-with-mcp). Accessed 2026-04-26. +- [`docs/copilot/agents/agent-tools`](https://code.visualstudio.com/docs/copilot/agents/agent-tools) — auto-approve / confirmation settings. Accessed 2026-04-26. +- [`docs/configure/profiles`](https://code.visualstudio.com/docs/configure/profiles) — profile-scoped user data. Accessed 2026-04-26. +- [`docs/configure/settings-sync`](https://code.visualstudio.com/docs/configure/settings-sync) — MCP Servers sync category. Accessed 2026-04-26. +- [`microsoft/vscode#253039`](https://github.com/microsoft/vscode/issues/253039) — auto-approve UX warning. Accessed 2026-04-26. +- [`modelcontextprotocol/servers#3460`](https://github.com/modelcontextprotocol/servers/issues/3460) — Windows `npx`/`.cmd` shim quirk. Accessed 2026-04-26. + +### Findings (2026-04-26) + +#### 1. Workspace MCP config — `.vscode/mcp.json` schema + +Workspace-scope MCP config lives at **`.vscode/mcp.json`** at the project root and is intended to be **committed to source control**: + +> "Workspace: create or open `.vscode/mcp.json` in your project. Include this file in source control to share MCP server configurations with your team." + +**Top-level keys** (per the [MCP configuration reference](https://code.visualstudio.com/docs/copilot/reference/mcp-configuration)): + +| Key | Required | Purpose | +|---|---|---| +| `servers` | yes | Object mapping server name → server config object. | +| `inputs` | no | Array of input-variable definitions (typed prompts) used to inject secrets at first-run. | + +> "The configuration file has two main sections: `servers: {}`… and `inputs: []`: an optional array of input variable definitions for sensitive information like API keys." + +There is **no `dev` top-level key**; the `dev` block is **per-server** (see §6). + +**Per-server fields — stdio:** + +| Field | Required | Description | +|---|---|---| +| `type` | yes | `"stdio"` (also valid: `"http"`, `"sse"`). May be omitted for stdio when `command` is present. | +| `command` | yes | Executable on `PATH` or full path (`npx`, `node`, `python`, `docker`, …). | +| `args` | no | Array of CLI args. | +| `env` | no | Map of env vars; supports `${input:id}` and predefined variables. | +| `envFile` | no | Path to a `.env` file to load additional vars (`"${workspaceFolder}/.env"`). | +| `sandboxEnabled` | no | `true` to sandbox the server. ⚠️ **macOS / Linux only — *not* available on Windows.** | +| `sandbox` | no | `{ filesystem: { allowWrite, denyRead, denyWrite }, network: { allowedDomains, deniedDomains } }`. | + +**Per-server fields — HTTP / SSE:** + +| Field | Required | Description | +|---|---|---| +| `type` | yes | `"http"` (preferred Streamable HTTP) or `"sse"` (legacy). VS Code "first tries the HTTP Stream transport and falls back to SSE if HTTP is not supported." | +| `url` | yes | Server URL. Also supports `unix:///…` and Windows `pipe:///pipe/…` socket forms. | +| `headers` | no | Map of HTTP headers, typically `{"Authorization": "Bearer ${input:api-token}"}`. | + +**Transports supported** (from the [MCP developer guide](https://code.visualstudio.com/api/extension-guides/ai/mcp)): + +> "Transports: Local standard input/output (`stdio`), Streamable HTTP (`http`), Server-sent events (`sse`) - legacy support." + +**Note:** the GitHub doc shows a `requestInit.headers` form, while VS Code's reference uses the flatter `headers`. ⚠️ Filed as **Q-025**. There is **no top-level `gallery` key** in `mcp.json`; the gallery is a UX surface (Extensions view → `@mcp` filter, plus `MCP: Browse MCP Servers`). + +**Minimal example:** + +```jsonc +{ + "servers": { + "github": { "type": "http", "url": "https://api.githubcopilot.com/mcp" }, + "playwright": { "command": "npx", "args": ["-y", "@microsoft/mcp-server-playwright"] } + } +} +``` + +#### 2. User-level MCP config on Windows — exact path + +**Profile-aware.** The doc says: + +> "User profile: run the **MCP: Open User Configuration** command to open the `mcp.json` file in your user profile folder. Servers configured here are available across all your workspaces. **When you use multiple profiles, each profile can have its own MCP server configuration.**" + +For the **Default profile** on Windows that resolves to: + +- **`%APPDATA%\Code\User\mcp.json`** — i.e. `C:\Users\\AppData\Roaming\Code\User\mcp.json`. + +For **named (non-default) profiles**, VS Code stores per-profile data under: + +- **`%APPDATA%\Code\User\profiles\\mcp.json`** — where `` is a generated short ID (not the human-readable name). + +> ⚠️ uncertain — the [Profiles](https://code.visualstudio.com/docs/configure/profiles) doc does not explicitly enumerate the per-profile `mcp.json` path; the location is inferred from the same convention used for `settings.json` per profile. The authoritative way to locate it is to invoke **MCP: Open User Configuration** in the desired profile. Filed as part of **Q-015** (resolved partially below). + +The **Insiders** equivalents replace `Code` with `Code - Insiders`. + +#### 3. Auth flow — secrets, OAuth, and `${input:…}` prompts + +**Three official patterns:** + +1. **Input variables (`${input:id}`)** — the recommended pattern for API-key-style secrets: + + > "Input variables let you define placeholders for configuration values, avoiding the need to hardcode sensitive information like API keys or passwords directly in the server configuration. When you reference an input variable using `${input:variable-id}`, **VS Code prompts you for the value when the server starts for the first time. The value is then securely stored for subsequent use.**" + + Definition lives in the top-level `inputs: []` array; reference lives in `env` or `headers`. Properties: `type` (`"promptString"`), `id`, `description`, `password` (boolean — masks input). + + Storage: VS Code persists the supplied value in the **OS secret store** (Windows Credential Manager via `vscode.SecretStorage`). To force re-prompting, run **MCP: Reset Trust** or delete the saved input via the Chat Customizations editor. ⚠️ uncertain — exact secret-storage namespace key on Windows is undocumented. Filed as part of **Q-025**. + +2. **`envFile`** — load a local `.env` file (kept out of source control): `"envFile": "${workspaceFolder}/.env"`. + +3. **OAuth / dynamic auth for HTTP servers** — the GitHub MCP server (`https://api.githubcopilot.com/mcp`) and other Copilot-aware HTTP servers use the **VS Code authentication providers** (OAuth flow shown in the trust prompt) rather than a manual `Authorization` header. For third-party HTTP servers without OAuth, use `headers: { "Authorization": "Bearer ${input:my-token}" }`. + +**Should `.vscode/mcp.json` be committed?** **Yes**, but only with `${input:…}` placeholders for any secret. The doc is explicit: + +> "**Important**: Avoid hardcoding sensitive information like API keys. Use input variables or environment files instead." + +This is the Copilot-native equivalent of Roo's split between "global `mcp_settings.json` (gitignored, has live tokens)" and "project `.roo/mcp.json` (committed, no tokens)" — Copilot collapses both into one committable file by virtue of `${input:…}`. See §8 for the migration recommendation. + +#### 4. Per-agent / per-toolset MCP filtering + +**There is no separate "allowedMcpServers" setting** in Copilot Chat outside the agent's `tools:` allowlist. Restriction is performed entirely at agent-load time via the [`.agent.md` `tools:` array](#custom-chat-modes-chatmodemd) (Phase 4a §1) and the [`*.toolsets.jsonc` `tools` array](#tool-sets) (Phase 4b §2): + +- An entry of `github/*` in `tools:` admits **all** tools from the `github` MCP server. +- An entry of `github/get_issue` admits **just that one** tool. +- Omitting all `/…` entries from `tools:` blocks the agent from using that MCP server entirely. + +> "A list of tool or tool set names that are available for this custom agent. Can include built-in tools, tool sets, MCP tools, or tools contributed by extensions. **To include all tools of an MCP server, use the `/*` format.**" — *quoted from the custom-agents doc, restated from Phase 4a §1* + +The chat input also exposes a **Configure Tools** picker that lets the user transiently disable individual MCP tools per session, but this is a UX layer on top of the same allowlist and doesn't survive across chat sessions. + +**Verdict:** Roo's per-mode `allowedMcpServers: ["github"]` ↔ Copilot's `.agent.md` `tools: ["github/*"]` is a **direct 1:1 mapping** with stronger granularity (per-tool, not just per-server). + +#### 5. Trust prompts and confirmation UX + +**First-run server trust:** + +> "When you add an MCP server to your workspace or change its configuration, you need to confirm that you trust the server and its capabilities before starting it. VS Code shows a dialog to confirm that you trust the server when you start a server for the first time." + +Trust decisions persist; reset via **MCP: Reset Trust**. **Important caveat:** + +> "**Warning**: If you start the MCP server directly from the `mcp.json` file, you will not be prompted to trust the server configuration." + +— meaning the inline "Start" code-lens in the editor bypasses the trust dialog (because opening the file is itself an explicit user action). + +**Per-tool confirmation policies** — the `chat.tools.*` settings family controls when the model can invoke a tool without asking (per [`docs/copilot/agents/agent-tools`](https://code.visualstudio.com/docs/copilot/agents/agent-tools)): + +| Setting | Description | +|---|---| +| `chat.tools.global.autoApprove` | Master "yolo" toggle — **strongly discouraged**, see [`microsoft/vscode#253039`](https://github.com/microsoft/vscode/issues/253039). | +| `chat.tools.eligibleForAutoApproval` | Per-tool allowlist for auto-approval. *(Org-managed.)* | +| `chat.tools.terminal.autoApprove` | Map of regex → allow/deny for `runInTerminal` commands. | +| `chat.tools.terminal.enableAutoApprove` | Master toggle for terminal auto-approve. | +| `chat.tools.urls.autoApprove` | Auto-approved URL patterns for fetch / browser tools. | +| `chat.agent.networkFilter` | Restricts which domains agent tools can reach. *(Org-managed.)* | + +For MCP server tools specifically, each tool invocation surfaces a confirmation dialog with options including **Allow once** / **Allow for this session** / **Allow for this workspace** / **Always allow**. The "always allow" choice is per-(workspace,tool) and persisted in workspace state. **Sandboxed servers (macOS/Linux only) auto-approve their own tool calls** because the sandbox already constrains them. + +#### 6. Discovery / installation flow + +**Installation surfaces** (per the [MCP developer guide](https://code.visualstudio.com/api/extension-guides/ai/mcp)): + +> "Users can add MCP servers within VS Code in several ways: +> - Install directly from the web: use a special MCP installation URL (`vscode:mcp/install`) on your website. +> - Workspace configuration: Specify the server configuration in a `.vscode/mcp.json` file in the workspace. +> - Global configuration: Define servers globally in the user profile. +> - Autodiscovery: VS Code can discover servers from other tools like Claude Desktop. +> - Extension: VS Code extensions can register MCP servers programmatically. +> - Command line: Install MCP servers from the command line with the `--add-mcp` VS Code command-line option." + +**MCP gallery:** browse via Extensions view (`@mcp` filter) or **MCP: Browse MCP Servers**. Installation writes to either user `mcp.json` or `.vscode/mcp.json` depending on the user's choice. + +**Server types supported:** + +- **NPX / Node** — `command: "npx", args: ["-y", "@scope/pkg"]` +- **Python / uv** — `command: "uvx", args: ["mcp-server-fetch"]` +- **Docker** — `command: "docker", args: ["run", "-i", "--rm", …]` (**must not** use `-d`; the doc warns "When using Docker with stdio servers, don't use the detach option (`-d`). The server must run in the foreground to communicate with VS Code.") +- **HTTP / SSE remote** — `type: "http"` or `type: "sse"` + +**Hot-reload `dev` block** (per-server): + +> "You can enable *development mode* for MCP servers by adding a `dev` key to the server configuration. This is an object with two properties: `watch` (file glob to watch) and `debug` (Node.js / Python debugging support)." + +Useful only for MCP-server *authors*; not relevant to vault migration. + +#### 7. Auto-import from Claude Desktop / Cursor / Continue + +> "VS Code can automatically detect and reuse MCP server configurations from other applications, such as Claude Desktop. With the `chat.mcp.discovery.enabled` setting, you can select one or more tools from which to discover their MCP server configuration." + +The setting is **disabled by default in current VS Code Stable** — the user must opt in and explicitly choose which source(s) to import. Reddit thread [r/ChatGPTCoding — "Try out MCP servers in VS Code"](https://www.reddit.com/r/ChatGPTCoding/comments/1jfr05y/try_out_mcp_servers_in_vs_code/) confirms: + +> "Add the setting `chat.mcp.discovery.enabled: true` to pick up MCP servers installed in Claude desktop, or create a `.vscode/mcp.json` config" + +⚠️ uncertain — official supported source list (Claude Desktop is confirmed; Cursor and Continue are inferred from community reports). Filed as part of **Q-025**. + +#### 8. Roo → Copilot MCP comparison (side-by-side) + +| Roo location / concept | Copilot equivalent | Notes | +|---|---|---| +| Global `~/AppData/Roaming/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/mcp_settings.json` | `%APPDATA%\Code\User\mcp.json` (Default profile) or `%APPDATA%\Code\User\profiles\\mcp.json` (named profiles) | Same shape (`mcpServers` → `servers`). Mechanical rename. | +| Project `.roo/mcp.json` | `.vscode/mcp.json` | Same intent (commit to repo). Same `mcpServers` → `servers` rename. | +| Per-mode `allowedMcpServers: ["github"]` (in `.roomodes` / `custom_modes.yaml`) | Per-agent `tools: ["github/*"]` (in `.github/agents/.agent.md`) | **Direct equivalent**, established in Phase 4a §5. Copilot is finer-grained. | +| Per-mode `allowedMcpServers: []` (empty array) | Per-agent `tools: [...]` with **no** `/…` entries | **Roo `[]` means "no MCP servers"** (truthy filter; see [`src/core/prompts/tools/native-tools/mcp_server.ts:22`](../../../src/core/prompts/tools/native-tools/mcp_server.ts:22)). Same in Copilot. **Resolves Q-009.** | +| Inline tokens in `mcp_settings.json` (vault-gitignored) | `${input:githubToken}` placeholder + first-run prompt + OS secret store | Recommended pattern for **commit safety**. The Copilot config can be safely committed because the placeholder resolves at runtime against Windows Credential Manager storage. | +| Global `mcp_settings.json` is **gitignored**; project `.roo/mcp.json` is **committed** | Single `mcp.json` (workspace) **plus** user `mcp.json` — both committable when secrets use `${input:…}` | The two-file split is no longer required for secret hygiene. | +| Per-server `disabled: true` flag in Roo | Enable/disable toggle in Extensions view (state stored separately from `mcp.json`) | Per the doc: "**The enable/disable state is stored separately from the server configuration in `mcp.json`, so it does not affect shared configuration files.**" | + +**Recommended Copilot-side equivalent of vault inline tokens:** + +```jsonc +{ + "inputs": [ + { "type": "promptString", "id": "githubToken", "description": "GitHub PAT for github MCP", "password": true }, + { "type": "promptString", "id": "tavilyKey", "description": "Tavily API key", "password": true }, + { "type": "promptString", "id": "context7Key","description": "Context7 API key", "password": true } + ], + "servers": { + "github": { + "command": "docker", + "args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"], + "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${input:githubToken}" } + }, + "tavily": { + "command": "docker", + "args": ["run", "-i", "--rm", "-e", "TAVILY_API_KEY", "mcp/tavily"], + "env": { "TAVILY_API_KEY": "${input:tavilyKey}" } + }, + "context7": { + "type": "http", + "url": "https://mcp.context7.com/mcp", + "headers": { "CONTEXT7_API_KEY": "${input:context7Key}" } + }, + "microsoft-learn": { + "type": "http", + "url": "https://learn.microsoft.com/api/mcp" + } + } +} +``` + +Drop this in `%APPDATA%\Code\User\mcp.json` (or `.vscode/mcp.json` for project-scoped). Each `${input:…}` triggers a one-time first-run secret prompt; values land in Windows Credential Manager and persist across sessions — eliminating the vault's need to gitignore the user-scope file. + +#### 9. Known limitations + +- **No documented hard cap on number of MCP servers**, but each enabled tool counts toward the **128-tool-per-request hard cap** (Phase 4b §7). With the vault's 4 enabled servers (`github` ~30 tools, `context7` 2 tools, `tavily` 5 tools, `microsoft-learn` 3 tools) the cap is comfortable; adding `filesystem` or `brave-search` plus all built-in tools could push it over. +- **No `denyList` for individual MCP tools** — access is allow-list only via `tools:`. To exclude one tool from a server with many tools, you must enumerate every other tool individually. +- **Sandboxing is unavailable on Windows** — per the doc: "**Sandboxing is currently not available on Windows.**" The `sandboxEnabled` / `sandbox` fields are silently ignored. Affects vault security posture: stdio MCP servers run with full user privileges on Windows. +- **`npx`-based stdio servers can fail silently on Windows when the shim isn't visible to `child_process.spawn`** — per [`modelcontextprotocol/servers#3460`](https://github.com/modelcontextprotocol/servers/issues/3460): "*This silently fails on Windows because npx is installed as `npx.cmd` (a batch script shim), and `child_process.spawn()` … does not resolve `.cmd` extensions automatically.*" VS Code Copilot generally invokes commands through a shell on Windows so plain `command: "npx"` works, but `nvm-windows`-managed Node versions can hide `npx` from VS Code's launched-from-shortcut env. Workaround: use the absolute path to `npx.cmd` (e.g. `C:\Program Files\nodejs\npx.cmd`) or wrap with `cmd /c npx …`. +- **Environment variable expansion** — `mcp.json` honors `${workspaceFolder}`, `${userHome}`, and `${env:VARNAME}` (per [VS Code variables reference](https://code.visualstudio.com/docs/reference/variables-reference)) but **not** Windows-style `%APPDATA%` literal expansion. Always use `${env:APPDATA}` or `${userHome}`. +- **Path separators** — backslashes in JSON must be escaped (`\\`); forward slashes also work on Windows for most APIs. +- **Docker stdio servers must not use `-d` (detach)** — see §6. +- **GitHub MCP HTTP server requires the org-level "MCP servers in Copilot" policy** for Copilot Business / Enterprise plans (per the GitHub doc). Personal accounts work without policy gating. + +#### Roo open questions resolved by this section + +- **Q-009** (semantics of `allowedMcpServers: []` vs unset) — **RESOLVED**: empty array means "no MCP servers" because the filter at [`src/core/prompts/tools/native-tools/mcp_server.ts:22`](../../../src/core/prompts/tools/native-tools/mcp_server.ts:22) treats an empty array as truthy and intersects to nothing. Vault's `code` mode therefore explicitly disables MCP. Copilot equivalent: omit all `/…` entries from `tools:`. +- **Q-015** (profile-scoped user-data folders) — **PARTIALLY RESOLVED for MCP**: per the explicit doc quote ("When you use multiple profiles, each profile can have its own MCP server configuration"), `mcp.json` **is** profile-scoped at `%APPDATA%\Code\User\profiles\\mcp.json`. The contradiction noted in Phase 4a §3 (where agents/instructions/prompts are NOT profile-scoped per [`microsoft/vscode#305642`](https://github.com/microsoft/vscode/issues/305642)) therefore appears to be **specific to the `prompts/` folder**, not to all user-data folders. The cleanest Phase-8 strategy: rely on profile-scoping for `mcp.json` and `settings.json`; rely on the global `prompts/` folder for `.agent.md` / `.prompt.md` / `.instructions.md` / `*.toolsets.jsonc`. + +## Tool Sets + +## Tool Sets + +### Sources + +- [`agent-tools — Group tools with tool sets`](https://code.visualstudio.com/docs/copilot/agents/agent-tools) — VS Code "Use tools with agents" doc, the canonical tool-sets reference. Accessed 2026-04-26. +- [`concepts/tools`](https://code.visualstudio.com/docs/copilot/concepts/tools) — VS Code "Tools" concept page. Accessed 2026-04-26. +- [`microsoft/vscode#251603`](https://github.com/microsoft/vscode/issues/251603) — open issue confirming `*.toolsets.jsonc` is stored "in the same directory as prompts and instructions files" (i.e. `%APPDATA%\Code\User\prompts\` on Windows). Accessed 2026-04-26. +- [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515) — open feature request: workspace-scoped `*.toolsets.jsonc` is **not yet supported** as of 2026-04-26. Accessed 2026-04-26. +- [`orgs/community#167721`](https://github.com/orgs/community/discussions/167721) — community thread showing a concrete tool-set file path on Linux: `~/.config/Code/User/prompts/.toolsets.jsonc`. Accessed 2026-04-26. +- [`vscode-copilot-release#13065`](https://github.com/microsoft/vscode-copilot-release/issues/13065) — confirms the **128-tool-per-request hard cap** is still enforced. Accessed 2026-04-26. + +### Findings (2026-04-26) + +#### 1. What is a tool set? + +Per the VS Code agent-tools doc: + +> "A tool set is a collection of tools that you can reference as a single entity in your prompts. Tool sets help you organize related tools and make them easier to use in a chat prompt, prompt files, and custom chat agents. Some of the built-in tools are part of predefined tool sets, such as `#edit` and `#search`." + +So a tool set is a **named bundle** of (a) built-in VS Code tools, (b) extension-contributed tools, and (c) MCP-server tools, addressable by a single `#` reference. Built-in sets (`#edit`, `#search`) ship with the product; user-defined sets live in `*.toolsets.jsonc` files. + +#### 2. File format & location + +**Filename pattern:** `*.toolsets.jsonc` (JSON-with-comments). + +**Location on Windows (user-scope):** `%APPDATA%\Code\User\prompts\` — the same folder used by `.prompt.md`, `.instructions.md`, and (per Q-015) user-scope `.agent.md` files. Per [`microsoft/vscode#251603`](https://github.com/microsoft/vscode/issues/251603): + +> "When using GitHub Copilot, the toolsets.jsonc file created is stored in the same directory as prompts and instructions files." + +And per [`orgs/community#167721`](https://github.com/orgs/community/discussions/167721) (Linux example, equivalent path scheme): + +> "The tool set can be found in `~/.config/Code/User/prompts/tiledb-mcp.toolsets.jsonc`." + +**Workspace-scope storage is NOT supported as of 2026-04-26.** [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515) is open, milestone "Backlog": + +> "I would like to request support for storing `.toolsets.jsonc` files directly within the workspace. This enhancement would enable projects to be fully workspace-configurable…" + +This is a **significant gap vs Roo**, where per-project `.roomodes` (and the modes' `groups` / `allowedMcpServers`) ride along with the repo. Filed as **Q-021**. The work-around is to put the `tools:` array inline on each `.agent.md` (which **does** support workspace storage at `.github/agents/`). + +**Schema** (canonical example from the VS Code doc): + +```jsonc +{ + "reader": { + "tools": ["search/changes", "search/codebase", "read/problems", "search/usages"], + "description": "Tools for reading and gathering context", + "icon": "book" + } +} +``` + +| Property | Type | Required | Description | +|---|---|---|---| +| top-level key | string | yes | The tool-set's name (referenced as `#`). | +| `tools` | string[] | yes | Tool names: built-in tools, extension tools, MCP tools (`servername/toolname` form). | +| `description` | string | no | Brief description shown in the tools picker. | +| `icon` | string | no | Product icon name (see [Product Icon Reference](https://code.visualstudio.com/api/references/icons-in-labels)). | + +⚠️ uncertain — the doc does not explicitly say whether MCP wildcard `servername/*` is allowed inside a tool set's `tools` array (it is allowed in `.agent.md` `tools:` per Phase 4a). Filed as **Q-022**. + +#### 3. How to create one + +> "1. Run the **Chat: Configure Tool Sets** command from the Command Palette and select **Create new tool sets file**. +> Alternatively, select the ellipsis (...) menu in the Chat view, select **Tool Sets**, and then select **Create new tool sets file**. +> 2. Define your tool set in the `.jsonc` file that opens." + +VS Code creates the file directly in `%APPDATA%\Code\User\prompts\` (Windows) and opens it in the editor. Multiple tool sets can live in one file (top-level keys); the convention seen in the wild ([community#167721](https://github.com/orgs/community/discussions/167721)) is one file per logical bundle named after the bundle. + +#### 4. How to reference a tool set from an agent or prompt + +In **chat input** (one-off): + +> "Reference a tool set in your prompts by typing `#` followed by the tool set name." + +In a **`.agent.md` `tools:` frontmatter array** (persistent): per the Phase 4a-cited custom-agents doc, the `tools` field accepts: + +> "A list of tool or tool set names that are available for this custom agent. Can include built-in tools, tool sets, MCP tools, or tools contributed by extensions. To include all tools of an MCP server, use the `/*` format." + +So `tools: [reader, edit, github/*]` resolves `reader` as a tool-set name and `github/*` as an MCP-server wildcard. **Confirmed: tool-set names are first-class entries in the agent's `tools:` array** (no special prefix required — they are looked up by the same name resolution as built-in tools). + +Same applies to a `.prompt.md`'s `tools:` array (same schema as agents). + +#### 5. MCP wildcard interaction + +- A `.agent.md` / `.prompt.md` `tools:` entry of `github/*` grants **all** tools from the `github` MCP server. +- A tool-set whose `tools` array contains `github/specific-tool` grants just that one tool. +- If both an agent's `tools:` entry `github/*` **and** a tool-set entry `github/specific-tool` are present, the union applies (the more permissive wins, since the wildcard already includes the specific tool). +- ⚠️ uncertain whether a tool set's `tools` array can itself contain a wildcard like `github/*` (Q-022). + +There is **no documented "deny" or "exclude" mechanism**: access is exclusively allow-list-based. To exclude one MCP tool from a server, you must enumerate every other tool individually instead of using `*`. + +#### 6. Comparison to Roo — closest analogue to `groups` + `allowedMcpServers` + +This is the headline mapping for Phase 4b. Roo's per-mode access control combines two fields: + +- `groups: ["read", "edit", "command", "mcp", "browser"]` — coarse-grained tool category allowlist (the entire `edit` group is one entry). +- `allowedMcpServers: ["github", "context7"]` — server-name allowlist that intersects with `groups: [..., "mcp"]`. + +Plus an inline per-group restriction: `groups: [["edit", { fileRegex: "\\.md$", description: "..." }]]`. + +The Copilot equivalents: + +| Roo construct | Copilot equivalent | Notes | +|---|---|---| +| `groups: ["read"]` | `tools: ["#search", "search/codebase", "search/usages", "read/problems", ...]` **or** `tools: [my-reader-toolset]` | Roo's "read" group expands to ~5 individual tools; bundling them in a `reader.toolsets.jsonc` set is the clean equivalent. The doc's own example **is exactly this** ("Tools for reading and gathering context"). | +| `groups: ["edit"]` | `tools: ["#edit"]` (the built-in `#edit` tool set) | Built-in `#edit` set already exists; quote: *"Some of the built-in tools are part of predefined tool sets, such as `#edit` and `#search`."* | +| `groups: ["command"]` | `tools: ["runInTerminal"]` (and friends) | No predefined "terminal" tool set; user must enumerate or define one. | +| `groups: ["mcp"]` | `tools: ["servername/*", "otherserver/*"]` — one wildcard per allowed server | Direct equivalent. | +| `allowedMcpServers: ["github", "context7"]` | `tools: ["github/*", "context7/*"]` **or** a tool set bundling them | Direct equivalent. | +| `groups: [["edit", { fileRegex: "\\.md$" }]]` | **No equivalent.** | Restated from Phase 4a. The `.agent.md` schema has no `applyTo`-style file-glob restriction on the `edit` tool. Lossy; must be enforced via prose ("only modify files matching `**/*.md`") or by removing `#edit` entirely. | +| Per-project `groups` / `allowedMcpServers` (lives in `.roomodes` in the repo) | `.agent.md` `tools:` inline, in `.github/agents/.agent.md` | Workspace-scoped tool **sets** are NOT yet supported (Q-021); workaround is to inline tool lists into the workspace-scoped agent file. | +| Global `customModes` `allowedMcpServers` (lives in `~/.../custom_modes.yaml`) | `.agent.md` in `%APPDATA%\Code\User\prompts\` + tool sets in the same folder | User-scope works fully. | + +**Verdict:** tool sets **plus** the agent `tools:` array **fully replicate** Roo's `groups` + `allowedMcpServers` semantics — *except* for (a) the per-tool file-glob restriction (`fileRegex`, no equivalent — restated from Phase 4a) and (b) workspace-scoped reusable tool **set** files (still user-scope only). For (b) the workaround is inline tool lists in `.github/agents/*.agent.md`. + +#### 7. Limits + +- **128-tool-per-request hard cap** — confirmed still in force. Per [`vscode-copilot-release#13065`](https://github.com/microsoft/vscode-copilot-release/issues/13065): + > "Reason: You may not include more than 128 tools in your request." + + Multiple users in 2025-Q3 reported hitting this with default tool sets plus a few MCP servers. **Tool sets do not bypass this**: the cap is on the flattened total of distinct tools sent to the model, not on the number of set-references. +- **Token-cost of tool sets in context** — each enabled tool's schema is serialized into the system prompt; large tool sets noticeably consume context. This is the practical reason Copilot recommends scoping each agent to a small set. +- **No documented nesting** — a tool set's `tools` array contains tool names, not other tool-set names. ⚠️ uncertain whether `#othersetname` inside a set's `tools` array is dereferenced; the schema doc only shows tool names. Filed as **Q-023**. +- **Secrets handling** — tool sets only reference tools; they do not contain credentials. Secrets for MCP servers live in `.vscode/mcp.json` / user MCP config (covered in Phase 4c). No secret material should appear in `*.toolsets.jsonc`. +- **Sync limitation** — per [`microsoft/vscode#251603`](https://github.com/microsoft/vscode/issues/251603), `*.toolsets.jsonc` files in `%APPDATA%\Code\User\prompts\` are **not yet** included in Settings Sync's "Prompts and Instructions" category as of mid-2025; the issue remains open. Affects multi-machine vault setups. Filed as **Q-024**. + +#### 8. Roo open questions resolved by this section + +- **Q-002** (per-mode MCP allowlists) — already resolved in Phase 4a via `tools: ["servername/*"]`; this section confirms the **toolset-bundled** alternative. +- **Q-005** (auto-conversion of `.roomodes`) — moves another step toward closure. The `groups` field can be mechanically expanded: `read` → built-in `#search` set + a custom `reader.toolsets.jsonc`; `edit` → `#edit`; `mcp` + `allowedMcpServers: [a, b]` → `["a/*", "b/*"]`. The remaining lossy field is still `fileRegex`. + +## Agent Mode + +### Sources + +- [`docs/copilot/chat/chat-agent-mode`](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode) — VS Code "Chat overview" (canonical Chat / agent-target / permission-level reference). Accessed 2026-04-26. +- [`docs/copilot/agents/overview`](https://code.visualstudio.com/docs/copilot/agents/overview) — VS Code "Using agents in Visual Studio Code" (built-in agents, agent types, hand-offs). Accessed 2026-04-26. +- [`docs/copilot/agents/agent-tools`](https://code.visualstudio.com/docs/copilot/agents/agent-tools) — VS Code "Use tools with agents" (permission levels, terminal auto-approve, sandboxing, 128-tool cap). Accessed 2026-04-26. +- [`docs/copilot/agents/subagents`](https://code.visualstudio.com/docs/copilot/agents/subagents) — VS Code "Subagents in Visual Studio Code" (canonical sub-agent / parallel-execution / nesting reference). Accessed 2026-04-26. +- [`docs/copilot/customization/custom-agents`](https://code.visualstudio.com/docs/copilot/customization/custom-agents) — VS Code "Custom agents in VS Code" (the `agents:` / `handoffs:` / `user-invocable` / `disable-model-invocation` frontmatter reference). Accessed 2026-04-26. +- [`docs/copilot/chat/chat-checkpoints`](https://code.visualstudio.com/docs/copilot/chat/chat-checkpoints) — VS Code "Revert changes with checkpoints and editing requests". Accessed 2026-04-26. +- [`docs/copilot/reference/copilot-settings`](https://code.visualstudio.com/docs/copilot/reference/copilot-settings) — `chat.agent.maxRequests`, `chat.agent.enabled`, `chat.agent.networkFilter`, etc. Accessed 2026-04-26. +- [`blogs/2026/02/05/multi-agent-development`](https://code.visualstudio.com/blogs/2026/02/05/multi-agent-development) — VS Code blog announcing parallel-subagent execution. Accessed 2026-04-26. +- [`blogs/2025/02/24/introducing-copilot-agent-mode`](https://code.visualstudio.com/blogs/2025/02/24/introducing-copilot-agent-mode) — original Feb-2025 agent-mode launch post. Accessed 2026-04-26. +- [`naonao-na.com — vscode-copilot-setting-agent-max-requests`](https://naonao-na.com/en/posts/vscode-copilot-setting-agent-max-requests/) — independent confirmation of `chat.agent.maxRequests` default = 25 and the "maximum requests reached / Continue" UX. Accessed 2026-04-26. +- [`docs.github.com — create custom agents`](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents) — GitHub Copilot cloud-coding-agent custom agents (same `.agent.md` schema, `target: github-copilot`). Accessed 2026-04-26. + +### Findings (2026-04-26) + +#### 1. What Agent mode is — vs Ask vs Plan vs Edit + +VS Code's chat dropdown surfaces **three built-in agents** plus any custom `.agent.md` agents: + +> "VS Code has three built-in agents: +> - **Agent**: autonomously plans and implements changes across files, runs terminal commands, and invokes tools. +> - **Plan**: creates a structured, step-by-step implementation plan before writing any code. Hands the plan off to an implementation agent when it looks right. +> - **Ask**: answers questions about coding concepts, your codebase, or VS Code itself without making file changes." + +The original Feb-2025 launch post characterizes Agent mode's loop as: + +> "Copilot agent mode operates in a more autonomous and dynamic manner to achieve the desired outcome. To process a request, Copilot loops over the following steps and iterates multiple times as needed… It can orchestrate your inner development flow while keeping you in control." + +Note that **Edit mode (the multi-file non-agentic editor) has been folded into Agent mode** in the current docs — the dropdown now shows Agent / Plan / Ask, not Agent / Edit / Ask. The "Working set" terminology has been replaced by Agent mode's autonomous file selection plus implicit-context attachments documented in the Chat-context page. + +#### 2. How to enable — settings + +| Setting | Default | Purpose | +|---|---|---| +| `chat.agent.enabled` | `true` | Master switch. **Org-managed**: an enterprise admin can disable it. | +| `chat.agent.maxRequests` | `25` | Cap on the number of model requests Agent mode can chain in one user turn before showing a "Continue" button. ([Settings reference](https://code.visualstudio.com/docs/copilot/reference/copilot-settings)) | +| `github.copilot.chat.agent.autoFix` | `true` | Auto-diagnose & fix lint/compile errors during the agent loop. | +| `chat.permissions.default` | (Default Approvals) | Persist a default permission level (`Default Approvals` / `Bypass Approvals` / `Autopilot`) across sessions. | +| `chat.autopilot.enabled` | `true` | Enables the Autopilot permission level in the picker. | +| `chat.checkpoints.enabled` | (varies) | Auto-snapshot files before each chat request so you can roll back. | +| `chat.editRequests` | (varies) | Allow editing prior chat requests, which reverts file changes from that request and after. | +| `chat.agent.sandbox.enabled` | `false` (org-managed) | Enable agent sandboxing on macOS/Linux. | +| `chat.agent.networkFilter` + `.allowedNetworkDomains` + `.deniedNetworkDomains` | (org-managed) | Restrict which domains agent tools (fetch, browser, MCP) can reach. | +| `chat.subagents.allowInvocationsFromSubagents` | `false` | Allow subagents to spawn further subagents (max nesting depth = 5). | + +Independent confirmation of the iteration cap: + +> "The default is 25. For complex tasks, increasing it to 50–100 helps Agent Mode complete without interruption." — [naonao-na.com](https://naonao-na.com/en/posts/vscode-copilot-setting-agent-max-requests/) + +#### 3. Tool-calling loop semantics + +The autonomous loop is described in the [Language Model Tool API guide](https://code.visualstudio.com/api/extension-guides/tools): + +> "1. Copilot determines the list of available tools… +> 2. Copilot sends the request to the LLM and provides it with the prompt, chat context, and the list of tool definitions… +> 3. If needed, Copilot invokes the suggested tool(s) with the parameter values provided by the LLM. A tool response might result in more requests for tool invocations. +> 4. If there are errors or follow-up tool requests, Copilot iterates over the tool-calling flow until all tool requests are resolved. +> 5. Copilot returns the final response to the user…" + +When the iteration count hits `chat.agent.maxRequests`, the loop pauses and surfaces a **Continue** button — the conversation is not lost; the user explicitly opts in to another batch of up to N requests. There is **no documented "auto-continue forever" mode** other than `Autopilot` permission level (see §5), which itself still respects `maxRequests` (Autopilot bypasses *approval* prompts, not the iteration cap). + +The agent can also push long-running terminal commands to the background — see §7. + +#### 4. File-edit confirmations and checkpoints + +Per the [Chat overview](https://code.visualstudio.com/docs/copilot/chat/chat-agent-mode): + +> "**Review inline diffs**: open a changed file to see inline diffs of the applied changes. Use the editor overlay controls to navigate between edits and **Keep** or **Undo** individual changes… +> **Use checkpoints**: VS Code can automatically create snapshots of your files at key points during chat interactions, enabling you to roll back to a previous state. +> **Stage to accept**: staging your changes in the Source Control view automatically accepts any pending edits." + +The "Working set" concept from the legacy Edit mode has been **replaced** by: + +- **Implicit context** (active file + selection auto-attached) plus `#file` / `#folder` / `#codebase` mentions for explicit context. +- **Chat checkpoints** (`chat.checkpoints.enabled`) — automatic per-request snapshots; restore via the **Restore Checkpoint** button on a prior request, with optional **Redo** and **Fork Conversation**. +- **Edit Previous Request** (`chat.editRequests`) — modify a sent prompt; VS Code reverts changes from that request and all subsequent ones, then resends. + +Per-edit confirmation defaults are governed by the **permission level** picker (see §5). The doc notes this is in addition to per-tool approvals: + +> "Both features [checkpoints and editing] complement the [review workflow](https://code.visualstudio.com/docs/copilot/chat/review-code-edits), where you accept or reject individual edits." + +#### 5. Permission levels (replace the legacy "auto-approve every edit" toggle) + +| Level | Description | +|---|---| +| **Default Approvals** | Tools that require approval show a confirmation dialog. The agent might ask clarifying questions. (Per-tool overrides via `chat.tools.eligibleForAutoApproval`, `chat.tools.terminal.autoApprove`, `chat.tools.urls.autoApprove`.) | +| **Bypass Approvals** | "Auto-approves all tool calls without showing confirmation dialogs and automatically retries on errors." | +| **Autopilot** (Preview) | "Auto-approves all tool calls, auto-responds to questions, and the agent continues working autonomously until the task is completed." Requires `chat.autopilot.enabled` (default on). | + +Cautionary quote: + +> "**Bypass Approvals** and **Autopilot** bypass manual approval prompts, including for potentially destructive actions like file edits, terminal commands, and external tool calls. The first time you enable either level, a warning dialog asks you to confirm." + +This is the modern equivalent of Roo's per-tool "Always allow" toggles — but at session scope, not per-tool. + +#### 6. Terminal command auto-approval (`chat.tools.terminal.autoApprove`) + +Per the [agent-tools doc](https://code.visualstudio.com/docs/copilot/agents/agent-tools): + +> "You can configure which terminal commands are automatically approved by using the `chat.tools.terminal.autoApprove` setting. You can specify both allowed and denied commands: +> - Set commands to `true` to automatically approve them +> - Set commands to `false` to always require approval +> - Use regular expressions by wrapping patterns in `/` characters" + +Example schema: + +```jsonc +{ + "mkdir": true, + "/^git (status|show\\b.*)$/": true, + "del": false, + "/dangerous/": false +} +``` + +Behaviour notes: + +- **Per-subcommand matching** by default; an `&&`-chained command is auto-approved only if **every** subcommand matches a `true` rule and none match a `false` rule. +- `matchCommandLine: true` switches to whole-line matching for advanced cases. +- **Org-managed kill switches:** `chat.tools.terminal.enableAutoApprove` (master), `chat.agent.networkFilter` (domain allow/deny for fetch + browser + MCP). +- **Sandboxed mode** (macOS/Linux only via `chat.agent.sandbox.enabled`) auto-approves terminal commands because they run in a constrained environment with `chat.agent.sandbox.FileSystem.{linux,mac}` allow/deny rules. **Not available on Windows** (restated from Phase 4c MCP findings). +- The `runInTerminal` agent tool uses the user's default shell **except** `cmd` on Windows and `sh` on macOS/Linux (no shell-integration); overridable via `chat.tools.terminal.terminalProfile.{windows,osx,linux}`. + +URL/network auto-approval is governed by `chat.tools.urls.autoApprove` with both `approveRequest` and `approveResponse` for granular pre/post approval — see Phase 4c MCP §5 for the same per-MCP-tool model. + +> ⚠️ **Caution from the doc:** *"Automatically approving terminal commands provides best effort protections and assumes the agent is not acting maliciously. It's important to protect yourself from prompt injection… Subverting auto approval is possible through various techniques such as quote concatenation. For example `find -exec` is normally blocked, but `find -e\"x\"ec` is not."* + +#### 7. Background / long-running tasks + +Local Agent mode has **two flavors of "background"**, neither of which is a true "fire-and-forget sub-conversation that finishes later": + +1. **Background terminal commands** — push a long-running terminal command (dev server, watch build) to the background while the agent continues with other tasks. Per [agent-tools doc](https://code.visualstudio.com/docs/copilot/agents/agent-tools): *"While a command is running, a **Continue in Background** button appears next to the terminal command in the chat conversation."* +2. **Hand-off to Copilot CLI or Cloud agent** — the [agents overview](https://code.visualstudio.com/docs/copilot/agents/overview) describes hand-offs as the way to "free up" the local IDE: *"create a plan with a local agent, hand off to Copilot CLI for proof of concepts, and then continue with a cloud agent to submit a pull request for team review."* This uses the **session-type dropdown** (Local / Copilot CLI / Cloud / Third-party). + +For a genuinely **autonomous background sub-task**, you escalate out of local Agent mode into: + +- **Copilot CLI** — same `.agent.md` files, runs in a Git worktree (Phase 5 scope). +- **Cloud agent** — same `.agent.md` files, runs on GitHub.com with PR integration (out of scope; see §10). + +There is **no "boomerang sub-task that returns later in the same chat without blocking the parent"** primitive in local Agent mode. Sub-agents (§8) are **synchronous to the parent agent** even when multiple subagents run *in parallel* — the parent waits for all of them to complete before continuing its own loop. + +#### 8. Sub-agent / hand-off support — the deep dive (Roo `new_task` parity) + +This is the headline section of Phase 4d. The picture has three distinct mechanisms that **together** approximate Roo's Orchestrator + `new_task` boomerang. + +##### 8.1 The built-in `agent` (a.k.a. `runSubagent`) tool + +Per the [Subagents doc](https://code.visualstudio.com/docs/copilot/agents/subagents): + +> "Subagents are typically **agent-initiated**, not directly invoked by users in chat. To allow the main agent to invoke subagents, make sure the `runSubagent` tool is enabled." + +The frontmatter name is `agent` (as it appears in `tools: ['agent']`); the underlying tool ID is `runSubagent`. Invocation is **model-driven**: + +> "1. You (or your custom agent's instructions) describe a complex task. +> 2. The main agent recognizes the part of the task that benefits from isolated context. +> 3. The agent starts a subagent, passing only the relevant subtask. +> 4. The subagent works autonomously and returns a summary. +> 5. The main agent incorporates the result and continues." + +What gets passed: a **prompt string** (the subtask) plus optionally an explicit model name. What comes back: **only the final result/summary** (intermediate tool calls are collapsed into a single expandable UI block). This is the closest 1:1 to Roo's `` "delegate to a fresh task and return a summary" semantics. + +##### 8.2 `agents:` frontmatter allowlist (which subagents this agent may invoke) + +Per the [Custom agents doc](https://code.visualstudio.com/docs/copilot/customization/custom-agents): + +> "`agents`: A list of agent names that are available as subagents in this agent. Use `*` to allow all agents, or an empty array `[]` to prevent any subagent use. If you specify `agents`, ensure the `agent` tool is included in the `tools` property." + +Combined with `user-invocable: false` and `disable-model-invocation: true`, this gives **per-agent declarative scoping** of the sub-agent graph. Example coordinator pattern from the doc: + +```markdown +--- +name: Feature Builder +tools: ['agent', 'edit', 'search', 'read'] +agents: ['Planner', 'Plan Architect', 'Implementer', 'Reviewer'] +--- +``` + +##### 8.3 `handoffs:` frontmatter (interactive next-step buttons, NOT autonomous) + +Distinct from sub-agents: + +> "Handoffs enable you to create guided sequential workflows that transition between agents with suggested next steps. After a chat response completes, **handoff buttons** appear that let users move to the next agent with relevant context and a pre-filled prompt." + +Each handoff: `{ label, agent, prompt, send, model }`. With `send: false` (default) the user reviews the prefilled prompt; with `send: true` it auto-submits. **Handoffs are user-mediated, not model-driven** — they're a UX widget, not a tool call. + +##### 8.4 Sequential vs parallel — Roo divergence + +Per the Feb-2026 multi-agent blog: + +> "What's new this release: VS Code can now run **multiple subagents in parallel**. Fire off multiple tasks at once, get results faster, and save premium requests in the process." + +And the [Subagents doc § Parallel code analysis](https://code.visualstudio.com/docs/copilot/agents/subagents) shows a concrete example prompt instructing the orchestrator to fan out four review subagents in parallel. + +**This is the inverse of Roo.** Roo's `new_task` is **strictly sequential and test-enforced** (see [`10-roo-inventory.md`](10-roo-inventory.md)). Copilot's subagents are **parallel by default when the model decides** (the model can choose to issue them serially via prompt instructions, but there is no `chat.subagents.forceSequential` setting in the [copilot-settings reference](https://code.visualstudio.com/docs/copilot/reference/copilot-settings)). + +⚠️ **Resolves Q-013** ("Which user workflows depend on Roo's sequential-only `new_task` semantics?"). Parity verdict: + +| Pattern | Roo | Copilot Chat sub-agents | +|---|---|---| +| One subtask at a time, parent waits | ✅ default & enforced | ✅ achievable (instruct the orchestrator to run subagents serially) | +| Many subtasks in parallel, parent waits for all | ❌ not supported | ✅ default capability | +| Subtask returns a structured summary to parent | ✅ via `attempt_completion` | ✅ via subagent's final assistant message (free-form) | +| Subtask runs in isolated context | ✅ | ✅ ("context-isolated agents that run independently from your main session — your main agent delegates work and only the final result flows back") | +| Subtask can use a different model than parent | ❌ uses parent's model | ✅ explicit param OR agent-configured `model:` (with cost-tier cap: *"The requested model cannot exceed the cost tier of the main model"*) | +| Recursive / self-referencing | ❌ blocked by tests | ✅ via `agents: [SelfName]` + `chat.subagents.allowInvocationsFromSubagents = true` (max nesting depth = 5) | + +**User-workflow risk for the migration:** + +- **No risk** for vault workflows that use `new_task` for sequential planning → implementation → review (the pattern still works; it just isn't *enforced*). The orchestrator's prompt simply needs to say "run these subagents in sequence" rather than relying on the runtime to serialize. +- **Risk** if the user has built workflows that **rely on the sequential ordering being honored even when the model would want to parallelize** — e.g. "Step 2 must read a file Step 1 just created." Mitigation: explicit prose ordering in the parent agent's instructions ("Wait for the Planner subagent to finish before invoking the Implementer"). +- **Net upside** for review/research/multi-perspective workflows that Roo cannot do at all today (parallel multi-perspective review, multi-model consensus). + +##### 8.5 Recursion caps + +> "By default, subagents cannot spawn further subagents. This prevents infinite recursion when agents accidentally call themselves in a loop… To enable nested subagents, enable the `chat.subagents.allowInvocationsFromSubagents` setting (`false` by default). When enabled, subagents can spawn their own subagents, **up to a maximum nesting depth of 5**." + +Self-referential agents are explicitly supported (the doc shows a `RecursiveProcessor` divide-and-conquer example). The depth-5 cap is **hard-coded**; not configurable per docs as of 2026-04-26. + +#### 9. Roo `new_task` boomerang vs Copilot sub-agent — final mapping + +| Roo Orchestrator pattern | Copilot Chat equivalent | Verdict | +|---|---|---| +| `code` from Orchestrator | Main agent declares `tools: ['agent']` + `agents: ['Code']`; LLM decides to call `runSubagent` with the message and target agent | **Functional equivalent** with three deltas: (a) parallel-capable, (b) model-decided not user-decided, (c) sub-agent return is a summary message, not a structured `` payload. | +| Sequential-only enforcement | None (model can parallelize; orchestrator must instruct sequential ordering in prose) | **Lost guarantee** — must be replaced with prompt discipline. | +| Each subtask runs in fresh chat context | Sub-agent runs in isolated context window | **1:1.** | +| Subtask result re-injected into Orchestrator's chat as a tool result | Sub-agent's final assistant message becomes a tool result for the parent | **1:1.** | +| Per-mode tool restrictions on the spawned subtask | Per-`.agent.md` `tools:` allowlist on the called subagent | **1:1, finer-grained.** | +| Per-mode `fileRegex` on the spawned subtask | None (restated from Phase 4a) | **Lossy.** | + +**Verdict:** Roo orchestrator `new_task` parity is **🟡 minor gap** (not 🔴 blocker) — Copilot sub-agents are **functionally a superset** (parallel + multi-model + nested), missing only Roo's strict sequential enforcement and the structured `attempt_completion` return-shape. Workflow migration requires re-writing orchestrator prompts to use prose ordering instead of relying on runtime serialization. + +#### 10. Cloud agent (Copilot coding agent on github.com) — 1-line note + +The same `.agent.md` schema is reused for the **Copilot coding agent** on github.com (delegated via the Cloud agent target or by assigning a GitHub issue to `copilot`); set `target: github-copilot` and use the `mcp-servers` frontmatter inline form. See [docs.github.com — create custom agents](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents). Out-of-scope here; revisit in Phase 5/8. + +#### Roo open questions resolved by this section + +- **Q-003** (sub-agent / orchestrator parity) — fully **CONFIRMED** with details: `agent` tool + `agents:` allowlist + `handoffs:` together cover the orchestrator pattern; **parallel by default** (newer than Roo) with optional sequential via prose; recursion behind a setting with depth-5 cap. +- **Q-013** (which user workflows depend on Roo's sequential-only semantics) — **RESOLVED**: only workflows that have an undeclared cross-step file/state dependency between subtasks. Migration mitigation = explicit prose ordering in the parent agent's instructions. Net effect is **🟡 minor** — see §8.4. + +## Chat Participants / Extension API + +### Sources + +- [`api/extension-guides/chat`](https://code.visualstudio.com/api/extension-guides/chat) — VS Code "Chat Participant API" (canonical reference for `vscode.chat.createChatParticipant`, `contributes.chatParticipants`, slash commands, follow-ups, participant detection). Accessed 2026-04-26. +- [`api/extension-guides/ai/chat`](https://code.visualstudio.com/api/extension-guides/ai/chat) — alternate URL for the same Chat Participant API doc. Accessed 2026-04-26. +- [`api/extension-guides/tools`](https://code.visualstudio.com/api/extension-guides/tools) and [`api/extension-guides/ai/tools`](https://code.visualstudio.com/api/extension-guides/ai/tools) — VS Code "Language Model Tool API" (`vscode.lm.registerTool`, `contributes.languageModelTools`). Accessed 2026-04-26. +- [`api/references/vscode-api#chat`](https://code.visualstudio.com/api/references/vscode-api#chat) — VS Code API reference (`ChatParticipant`, `ChatRequestHandler`, `ChatResponseStream`, `ChatFollowupProvider`). Accessed 2026-04-26. +- [`docs/copilot/customization/agent-plugins`](https://code.visualstudio.com/docs/copilot/customization/agent-plugins) — VS Code "Agent plugins in VS Code (Preview)" — the supported way for a plugin to ship custom agents (`.agent.md`), skills, hooks, and MCP servers declaratively. Accessed 2026-04-26. +- [`docs/copilot/customization/custom-agents § FAQ`](https://code.visualstudio.com/docs/copilot/customization/custom-agents#_frequently-asked-questions) — confirms extensions can contribute custom agents. Accessed 2026-04-26. +- [`docs/copilot/reference/copilot-vscode-features`](https://code.visualstudio.com/docs/copilot/reference/copilot-vscode-features) — Copilot in VS Code cheat sheet (canonical built-in chat-participants list). Accessed 2026-04-26. +- [`github.com/microsoft/vscode-extension-samples — chat-sample`](https://github.com/microsoft/vscode-extension-samples/tree/main/chat-sample) — official `@cat` chat-participant sample (the reference exemplar). Accessed 2026-04-26. + +### Findings (2026-04-26) + +#### 1. Built-in chat participants + +Per the [Copilot cheat sheet](https://code.visualstudio.com/docs/copilot/reference/copilot-vscode-features): + +| Participant | One-liner | +|---|---| +| `@github` | "Use the `@github` participant to ask questions about GitHub repositories, issues, pull requests, and more." Powers GitHub.com / GHE knowledge skills. Example: `@github What are all of the open PRs assigned to me?` | +| `@terminal` | "Use the `@terminal` participant to ask questions about the integrated terminal or shell commands." Example: `@terminal list the 5 largest files in this workspace` | +| `@vscode` | "Use the `@vscode` participant to ask questions about VS Code features, settings, and the VS Code extension APIs." Example: `@vscode how to enable word wrapping?` | +| `@workspace` | (Documented in [Chat Participant API guide](https://code.visualstudio.com/api/extension-guides/chat)) "Built-in `@workspace` … is powered by multiple tools: GitHub's knowledge graph, combined with semantic search, local code indexes, and VS Code's language services." | + +Built-in participants take precedence in the participant-detection routing: + +> "**Built-in chat participants take precedence** for participant detection. For example, a chat participant that operates on workspace files might conflict with the built-in `@workspace` participant." + +#### 2. Third-party chat participants via `vscode.chat.createChatParticipant` + +A VS Code extension contributes a chat participant by: + +1. Declaring `contributes.chatParticipants` in `package.json`: + + ```jsonc + "contributes": { + "chatParticipants": [{ + "id": "chat-sample.my-participant", + "name": "my-participant", + "fullName": "My Participant", + "description": "What can I teach you?", + "isSticky": true, + "commands": [ + { "name": "teach", "description": "…" }, + { "name": "play", "description": "…" } + ] + }] + } + ``` + +2. Registering a `ChatRequestHandler` at activation time: + + > "On activation of the extension, create the participant with `vscode.chat.createChatParticipant`. Provide the ID, which you defined in `package.json`, and a reference to the request handler that you implement…" + + ```ts + const cat = vscode.chat.createChatParticipant('chat-sample.my-participant', handler); + ``` + +3. The handler signature: + + ```ts + const handler: vscode.ChatRequestHandler = async ( + request: vscode.ChatRequest, + context: vscode.ChatContext, + stream: vscode.ChatResponseStream, + token: vscode.CancellationToken + ): Promise<…> => { … }; + ``` + +4. Optional: slash commands (`commands` array in `package.json`), follow-ups (`ChatFollowupProvider`), participant detection (`disambiguation` array of `{ category, description, examples }`), and feedback telemetry (`onDidReceiveFeedback`). + +The participant **owns the conversation turn** when invoked: it receives the user prompt and orchestrates everything itself (including sub-tool-calls via the Language Model API), in contrast to language-model tools which the agent loop invokes opportunistically. + +> "Chat participants are different from [language model tools](https://code.visualstudio.com/api/extension-guides/ai/tools) that are invoked as part of the LLM orchestrating the steps needed to resolve the user's chat prompt. **Chat participants receive the user's prompt and orchestrate the tasks that are needed themselves.**" + +Convention: at most **one chat participant per extension**: + +> "Up to one chat participant per extension is a simple model that scales well in the UI." + +#### 3. Third-party tools via the Language Model Tools API + +Distinct from chat participants. Two-step contract: + +1. Declare in `contributes.languageModelTools` in `package.json`: + + ```jsonc + "languageModelTools": [{ + "name": "chat-tools-sample_tabCount", + "tags": ["editors", "chat-tools-sample"], + "toolReferenceName": "tabCount", + "displayName": "Tab Count", + "modelDescription": "The number of active tabs in a tab group in VS Code.", + "userDescription": "Count the number of active tabs in a tab group.", + "canBeReferencedInPrompt": true, + "icon": "$(files)", + "inputSchema": { "type": "object", "properties": { } }, + "when": "debugState == 'running'" + }] + ``` + +2. Register at activation: + + ```ts + vscode.lm.registerTool('chat-tools-sample_tabCount', new TabCountTool()); + ``` + + Implement `vscode.LanguageModelTool` with `prepareInvocation` (confirmation message) and `invoke` (returns `vscode.LanguageModelToolResult`). + +These tools are invoked by the agent loop automatically when the LLM decides they're relevant, the same way MCP-server tools are. They appear in the Configure Tools picker, can be referenced from a prompt with `#tabCount`, and can be allowlisted in an `.agent.md` `tools:` array (via either the `name` or the `toolReferenceName`). + +The Language Model Tools API is **the recommended path for "I want to ship a custom tool to all Copilot users"** — it deeply integrates with the editor (full `vscode.*` API access) but cannot run outside VS Code. The MCP-server alternative is the right choice when you want cross-tool reuse (Copilot CLI, cloud agent, third-party clients). + +#### 4. Extension-contributed `.agent.md` files — Plan-B viability assessment + +**Yes, extensions can ship custom agents declaratively.** Two routes: + +**Route A — Agent plugins (Preview, the supported declarative way):** + +Per the [Agent plugins doc](https://code.visualstudio.com/docs/copilot/customization/agent-plugins): + +> "Agent plugins are prepackaged bundles of chat customizations that you can discover and install from plugin marketplaces in Visual Studio Code. **A single plugin can provide any combination of slash commands, agent skills, custom agents, hooks, and MCP servers.**" + +Plugins are toggled by the `chat.plugins.enabled` org-managed setting, are installable from a Git repo URL via `Chat: Install Plugin From Source`, and appear in the **Agent Plugins — Installed** view in the Extensions side panel. **This is the sanctioned path for shipping a "Roo-replacement extension that bundles a complete vault-style mode set."** + +**Route B — Bundled in a regular VS Code extension (also supported):** + +Per the [Custom agents FAQ](https://code.visualstudio.com/docs/copilot/customization/custom-agents#_frequently-asked-questions): + +> "To remove a custom agent that was contributed by an extension, you need to uninstall the extension that provides it. If you don't want to uninstall the extension, you can hide the custom agent from the agents dropdown instead." + +The doc doesn't enumerate the exact contribution-point name for "extension ships an `.agent.md`" outside the plugins framework, but the FAQ language confirms it works today. ⚠️ uncertain — exact contribution-point manifest entry and whether plain extensions need a manifest entry vs just placing files. Filed as **Q-027**. + +**Plan-B viability for a "Roo-replacement extension":** ✅ **viable**. A single agent plugin (or extension) can ship: 17 vault `.agent.md` files + `.toolsets.jsonc` files + `mcp.json` server registrations + hooks for pre/post-tool actions + slash commands. The user installs one VSIX/plugin, gets the entire vault. This is meaningfully different from Roo's "extension owns its own UI" model (see §5). + +#### 5. Architectural comparison — Roo extension vs Copilot extension API + +| Axis | Roo (current) | Copilot Chat (extension API) | +|---|---|---| +| Chat surface ownership | Roo extension owns its own webview chat panel ([`webview-ui/src/`](../../../webview-ui/src)) | Extensions contribute *into* the built-in Copilot Chat panel; cannot own a parallel chat surface | +| Tool surface | 22 native tools hard-coded in [`src/core/prompts/tools/native-tools/`](../../../src/core/prompts/tools/native-tools) + MCP | Built-in agent loop tools + MCP + extension-contributed `vscode.lm.registerTool` + extension-contributed chat participants | +| Mode/agent surface | YAML mode definitions in `.roomodes` / `custom_modes.yaml` | `.agent.md` files in `.github/agents/` + user prompts folder + extension-shipped via Agent Plugins | +| Settings/restrictions UI | Custom React panels: [`ModesView.tsx`](../../../webview-ui/src/components/modes/ModesView.tsx), [`McpServerRestriction.tsx`](../../../webview-ui/src/components/modes/McpServerRestriction.tsx), [`DeleteModeDialog.tsx`](../../../webview-ui/src/components/modes/DeleteModeDialog.tsx) | Command Palette + JSON editor + the **Chat Customizations editor** (Preview) — no per-mode visual restriction picker | +| User experience | Two chat panels in the activity bar (Copilot + Roo) | One unified chat panel; agents are dropdown items | +| Discovery | Roo extension on the Marketplace | Copilot extension + Agent Plugins gallery + `chat.plugins.enabled` | + +**User-visible implication:** migrating to a Copilot-Chat-only world **collapses two chat panels into one** but loses Roo's bespoke per-mode UI affordances. The user gains (a) a single unified chat surface, (b) cross-tool agent files (the same `.agent.md` runs locally, in Copilot CLI, and on the cloud agent), but loses (c) the visual mode editor and the visual MCP-server restriction picker — those become Markdown frontmatter editing. + +#### 6. Reference exemplar + +**Official sample:** [`microsoft/vscode-extension-samples — chat-sample`](https://github.com/microsoft/vscode-extension-samples/tree/main/chat-sample) implements the `@cat` participant (the running example throughout the Chat Participant API guide). It demonstrates `createChatParticipant`, slash commands (`/teach`, `/play`), follow-up provider, button responses, and `prompt-tsx` for prompt construction. It also contains a parallel `tools.ts` showing `vscode.lm.registerTool` and a `chatUtilsSample.ts` showing the `@vscode/chat-extension-utils` library for tool-calling-from-participant. + +**Real-world example with `.agent.md` shipped in an extension blog post:** [Microsoft Tech Community — VS Code Custom Agents: AI-Powered Terraform Security Scanning in the IDE](https://techcommunity.microsoft.com/blog/azureinfrastructureblog/vs-code-custom-agents-ai-powered-terraform-security-scanning-in-the-ide/4507903) — confirms the broader pattern of shipping a domain-specific custom agent file from a repository, viable for both team-shared `.github/agents/` and Marketplace plugin distribution. + +#### Roo open questions resolved / opened by this section + +- **Q-014** (which webview affordances does the user actually rely on day-to-day) — **PARTIALLY RESOLVED in mapping**: the visual-mode-editor + visual-MCP-restriction-picker do not carry over; they become JSON/frontmatter editing or the Chat Customizations editor. Whether this is a daily-driver blocker remains a user-input question (still owned by Phase 1 follow-up). +- **Q-027** (new) — Exact contribution-point manifest entry for plain (non-plugin) VS Code extensions to ship `.agent.md` files. The FAQ confirms this is possible; the schema entry isn't documented in the Custom Agents page. +- **Q-028** (new) — Org-management story for Agent Plugins: are organization-wide plugin installs supported, and does the existing `chat.plugins.enabled` org-management policy interact with the `github.copilot.chat.organizationCustomAgents.enabled` org-policy from Phase 4a? + +## Storage Locations (Windows) + +### Sources + +- All sources cited in Phase 4a, 4b, 4c above (custom-agents, custom-instructions, prompt-files, agent-tools, mcp-servers, mcp-configuration, profiles, settings-sync). Re-cited inline in the table below as needed. +- [`docs/configure/profiles`](https://code.visualstudio.com/docs/configure/profiles) — VS Code Profiles. Accessed 2026-04-26. +- [`docs/configure/settings-sync`](https://code.visualstudio.com/docs/configure/settings-sync) — Settings Sync (sync categories include "Prompts and Instructions" and "MCP Servers"). Accessed 2026-04-26. +- [`microsoft/vscode#272199`](https://github.com/microsoft/vscode/issues/272199) — confirms `%APPDATA%\Code\User\prompts\` for `.instructions.md`. Accessed 2026-04-26. +- [`microsoft/vscode#305642`](https://github.com/microsoft/vscode/issues/305642) — confirms only the global `prompts/` folder is scanned (not profile-scoped) for agents/instructions/prompts. Accessed 2026-04-26. +- [`microsoft/vscode-copilot-release#12853`](https://github.com/microsoft/vscode-copilot-release/issues/12853) — confirms `%APPDATA%\Code\User\prompts\` is shared by `.prompt.md`, `.instructions.md`, tool sets. Accessed 2026-04-26. +- [`microsoft/vscode#251603`](https://github.com/microsoft/vscode/issues/251603) — `*.toolsets.jsonc` not in Settings Sync (Q-024). Accessed 2026-04-26. +- [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515) — workspace-scoped tool sets not yet supported (Q-021). Accessed 2026-04-26. + +### Findings (2026-04-26) — Consolidated reference table + +All Windows paths assume **VS Code Stable, Default profile**. Substitute `Code` → `Code - Insiders` for VS Code Insiders, and prepend `%APPDATA%\Code\User\profiles\\` instead of `%APPDATA%\Code\User\` for **named profiles** where noted. + +| Concept | Workspace path | Windows user path | Sync'd via Settings Sync? | +|---|---|---|---| +| Custom agents (`.agent.md`) | `.github/agents/*.agent.md` (and `.claude/agents/*.md`) | `%USERPROFILE%\.copilot\agents\` **and/or** `%APPDATA%\Code\User\prompts\` (NOT profile-scoped — see [`vscode#305642`](https://github.com/microsoft/vscode/issues/305642)) | ✅ via "Prompts and Instructions" sync category (per [Settings Sync doc](https://code.visualstudio.com/docs/configure/settings-sync); same folder as prompts) | +| Prompt files (`.prompt.md`) | `.github/prompts/*.prompt.md` | `%APPDATA%\Code\User\prompts\` (per [`vscode-copilot-release#12853`](https://github.com/microsoft/vscode-copilot-release/issues/12853)) | ✅ via "Prompts and Instructions" | +| Instruction files (`.instructions.md`) | `.github/instructions/*.instructions.md` | `%APPDATA%\Code\User\prompts\` (per [`vscode#272199`](https://github.com/microsoft/vscode/issues/272199)) and/or `%USERPROFILE%\.copilot\instructions\` and/or `%USERPROFILE%\.claude\rules\` | ✅ via "Prompts and Instructions" | +| Repo-wide instructions | `.github/copilot-instructions.md` | n/a | n/a (per-repo) | +| AGENTS.md (always-on) | `AGENTS.md` (project root); nested per-folder behind `chat.useNestedAgentsMdFiles` | n/a | n/a (per-repo) | +| CLAUDE.md (always-on, behind `chat.useClaudeMdFile`) | `CLAUDE.md`, `.claude/CLAUDE.md`, `CLAUDE.local.md` | `~/.claude/CLAUDE.md` | n/a (per-repo, except the home-dir one) | +| Tool sets (`*.toolsets.jsonc`) | ❌ not yet supported (Q-021 — [`vscode#251515`](https://github.com/microsoft/vscode/issues/251515)) | `%APPDATA%\Code\User\prompts\*.toolsets.jsonc` (per [`vscode#251603`](https://github.com/microsoft/vscode/issues/251603)) | ⚠️ Q-024 — [`vscode#251603`](https://github.com/microsoft/vscode/issues/251603) reports the file is **not** included in the "Prompts and Instructions" sync category as of mid-2025; status not re-verified. | +| MCP config | `.vscode/mcp.json` | `%APPDATA%\Code\User\mcp.json` (Default profile) **or** `%APPDATA%\Code\User\profiles\\mcp.json` (named profiles — profile-aware per [MCP servers doc](https://code.visualstudio.com/docs/copilot/customization/mcp-servers): *"When you use multiple profiles, each profile can have its own MCP server configuration"*) | ✅ via dedicated **"MCP Servers"** Settings Sync category (per [MCP servers doc § Synchronize MCP configuration across devices](https://code.visualstudio.com/docs/copilot/customization/mcp-servers)) | +| MCP server enable/disable state | `.vscode/` workspace state (not in `mcp.json`) | profile state (not in `mcp.json`) | ⚠️ uncertain — the doc says enable/disable state is "stored separately from the server configuration in `mcp.json`, so it does not affect shared configuration files"; whether that separate state is itself synced is undocumented. Filed as part of **Q-025**. | +| MCP server secrets (`${input:…}` resolved values) | n/a | Windows Credential Manager (via `vscode.SecretStorage`); profile-scoped per profile | ❌ never synced (secrets are device-local by design) | +| Chat history / state | `.vscode/` workspace state (chat sessions per workspace) | `%APPDATA%\Code\User\workspaceStorage\\` (per workspace) and `%APPDATA%\Code\User\globalStorage\` (cross-workspace) | ❌ chat sessions are not in any sync category | +| `chat.promptFilesLocations`, `chat.instructionsFilesLocations`, `chat.agentFilesLocations`, `chat.mcp.discovery.enabled`, `chat.tools.*`, `chat.useAgentsMdFile`, `chat.useClaudeMdFile`, etc. (workspace-scoped overrides) | `.vscode/settings.json` | `%APPDATA%\Code\User\settings.json` (Default profile) **or** `%APPDATA%\Code\User\profiles\\settings.json` (named profiles) | ✅ via "Settings" sync category | +| GitHub Copilot extension state (cached models, MRU agents, etc.) | n/a | `%APPDATA%\Code\User\globalStorage\github.copilot-chat\` and `\github.copilot\` | ❌ extension state is per-device | +| Settings Sync identity / conflict log | n/a | `%APPDATA%\Code\User\sync\` | n/a (the sync mechanism's own state) | +| Windows Copilot CLI MCP config (Phase 5 — separate from VS Code) | n/a | `%USERPROFILE%\.copilot\mcp-config.json` (per Squad / Copilot CLI conventions; verify in Phase 5) | ❌ not part of VS Code Settings Sync | + +#### Profile-aware paths and symlink implications for the vault + +VS Code's **profile** mechanism segregates user data into `%APPDATA%\Code\User\profiles\\` for everything **except** the shared global `prompts/` folder (and a handful of other always-global folders). The split as currently understood (with `mcp.json` resolved this section, others from Phase 4a/4b): + +| Per-profile (segregated) | Global (shared across profiles) | +|---|---| +| `settings.json` | `prompts/` (agents, prompts, instructions, tool sets — per [`vscode#305642`](https://github.com/microsoft/vscode/issues/305642)) | +| `keybindings.json` | `globalStorage/` (extension state, by design) | +| `snippets/` | Settings Sync identity (`sync/`) | +| `mcp.json` (this section's finding) | Windows Credential Manager (OS-level) | +| `tasks.json` | | +| Extensions list | | + +**Vault implication:** the [`../roo-vault/setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1) pattern of using **directory symlinks** (e.g. `mklink /D %APPDATA%\Code\User\prompts c:\git\roo-vault\global-settings\prompts`) maps cleanly because: + +- The `prompts/` folder is **global**, so a single symlink at `%APPDATA%\Code\User\prompts` is correctly seen by all profiles. ✅ +- `mcp.json` is **profile-scoped**, so the vault must either (a) symlink `%APPDATA%\Code\User\mcp.json` for the Default profile only and accept that named profiles need their own copy/link, or (b) symlink each profile's `%APPDATA%\Code\User\profiles\\mcp.json` individually. ⚠️ The user reportedly uses only the Default profile, so option (a) is sufficient for the immediate migration; multi-profile support is a Phase 8 follow-up. +- `settings.json` is **profile-scoped**; same caveat as `mcp.json`. +- Settings Sync (when enabled with the **MCP Servers** category checked) provides a parallel cloud-backed sync of `mcp.json` across machines and is **complementary** to the symlink-into-vault pattern — they aren't mutually exclusive, but pick one to be the source of truth to avoid conflicts. + +**Resolves Q-008 (vault symlink portability for Copilot Chat)** at a fundamental level for the prompts/agents/instructions/tool-sets surface: directory symlinks at `%APPDATA%\Code\User\prompts\` are correctly read by VS Code (no sandbox/permission rejection). MCP `mcp.json` symlinks at the profile root are also tolerated, with the profile-scoping caveat noted above. Filed remaining edge cases (per-profile symlinking automation, sync conflict avoidance) as **Q-026**. + +## Limits / Known Gaps + +### Sources + +- All sources cited in Phase 4a/4b/4c/4d above (Custom Agents, Custom Instructions, Prompt Files, Tool Sets, MCP, Agent Mode, Sub-agents, Chat Participants, Language Model Tools, Agent Plugins). Re-cited inline in the gap entries below as needed. +- [`docs/copilot/agents/agent-tools § 128 cap`](https://code.visualstudio.com/docs/copilot/agents/agent-tools) — restated. Accessed 2026-04-26. +- [`vscode-copilot-release#13065`](https://github.com/microsoft/vscode-copilot-release/issues/13065) — restated. Accessed 2026-04-26. +- [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515) — restated. Accessed 2026-04-26. +- [`microsoft/vscode#251603`](https://github.com/microsoft/vscode/issues/251603) — restated. Accessed 2026-04-26. +- [`docs/copilot/chat/chat-sessions`](https://code.visualstudio.com/docs/copilot/chat/chat-sessions) — multi-session / fork / archive behavior. Accessed 2026-04-26. + +### Findings (2026-04-26) — Gap Catalog + +This section synthesizes the **Roo → Copilot Chat capability deltas** uncovered across Phase 4a–4d. Each row carries a severity flag for Phase 6's gap matrix: + +- 🔴 **blocker** — no equivalent and no acceptable workaround; would force the user to keep Roo for that workflow +- 🟠 **major** — no first-class equivalent but a workable workaround exists with effort +- 🟡 **minor** — different ergonomics; functionality preserved with prompt/process changes +- ✅ **no gap** — Copilot matches or exceeds Roo + +#### Gaps (things Roo does that Copilot Chat doesn't) + +| # | Capability | Roo behavior | Copilot Chat status | Severity | Workaround / notes | +|---|---|---|---|---|---| +| G-1 | **Per-mode file-glob edit restrictions** (`fileRegex`) | `groups: [["edit", { fileRegex: "\\.md$" }]]` hard-blocks edits outside the regex | `.agent.md` has **no `fileRegex` / `applyTo` field** for the edit tool (confirmed Phase 4a §5(a)) | 🔴 | Inline prose ("only modify files matching `**/*.md`"); or omit `edit` from `tools:` (blocks **all** edits, not selective ones). Real loss for the Architect mode's `.md`-only guard. | +| G-2 | **Per-mode rules folder** (`.roo/rules-/`) | Mode-specific Markdown rule files auto-loaded only when that mode is active | No first-class equivalent; instructions are scoped by file glob (`applyTo`), not by agent (Phase 4a Q-018) | 🟠 | Inline rules into the `.agent.md` body, or Markdown-link to dedicated `.instructions.md` files from the agent body. Re-architects per-mode rules into per-agent linked-content. | +| G-3 | **Workspace-scoped tool sets** (`.vscode/*.toolsets.jsonc`) | n/a (Roo encodes tool groups inline in `.roomodes`) | `*.toolsets.jsonc` is **user-scope only**; workspace storage tracked in [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515), not yet shipped (Q-021) | 🟠 | Inline `tools:` arrays in `.github/agents/.agent.md` (workspace-scoped). Re-evaluate when issue ships. | +| G-4 | **Sequential-only `new_task` orchestration** | Test-enforced sequential subtask execution ([`new-task-isolation.spec.ts`](../../../src/core/task/__tests__/new-task-isolation.spec.ts)) | Sub-agents are **parallel-capable by default** (Phase 4d §8.4); no setting forces sequential | 🟡 | Prose discipline in the parent agent's body ("run subagents in this order, wait for each"). Net upside elsewhere (parallel review, multi-model consensus). **Resolves Q-013.** | +| G-5 | **Native webview UI for editing modes / MCP / rules** | [`ModesView.tsx`](../../../webview-ui/src/components/modes/ModesView.tsx), [`McpServerRestriction.tsx`](../../../webview-ui/src/components/modes/McpServerRestriction.tsx), [`DeleteModeDialog.tsx`](../../../webview-ui/src/components/modes/DeleteModeDialog.tsx) | Command Palette + JSON/Markdown editor + Chat Customizations editor (Preview); no visual MCP-server restriction picker (Phase 4d §5) | 🟡 | Acceptable for power users (vault is already file-driven). Lossy for new-user onboarding; documentation-mitigable. | +| G-6 | **Multi-thread chat sessions per workspace** | Roo: one task at a time; subtasks are sequential | Copilot: **multi-session**; the Chat view "Sessions list" supports many concurrent local + CLI + cloud sessions per workspace, plus fork-from-checkpoint ([chat-sessions doc](https://code.visualstudio.com/docs/copilot/chat/chat-sessions)) | ✅ | Copilot is **better here** — confirmed multi-session UX. | +| G-7 | **128-tool-per-request hard cap** | n/a (Roo's 22 native + per-mode MCP allowlist stays well under) | Hard 128-tool cap per request ([`vscode-copilot-release#13065`](https://github.com/microsoft/vscode-copilot-release/issues/13065); restated Phase 4b §7) | 🟡 | Per-agent `tools:` allowlists keep counts low; enable `github.copilot.chat.virtualTools.threshold` to auto-collapse large tool sets. With the vault's 4 enabled MCP servers + built-ins, the cap is comfortable today. | +| G-8 | **Settings Sync coverage gaps** | Roo settings live in extension globalStorage + `~/.roo/`; user manages sync manually | "Prompts and Instructions" Settings-Sync category covers `.agent.md` / `.prompt.md` / `.instructions.md`, but **`*.toolsets.jsonc` is reportedly NOT included** ([`microsoft/vscode#251603`](https://github.com/microsoft/vscode/issues/251603); Q-024) | 🟡 | Vault symlink scheme already covers this; pure Settings-Sync users hit it. | +| G-9 | **Chat history portability / export** | Roo serializes task history to extension globalStorage; exportable via DB queries | Chat sessions stored in `%APPDATA%\Code\User\workspaceStorage\\` per workspace; **no documented portable export format** for sessions; `Fork Conversation` only works in-app | 🟠 | Phase-8 follow-up: investigate whether the chat-sessions JSON is human-parseable. Filed as **Q-029**. | +| G-10 | **Custom approval policies per tool / MCP server** | Roo: per-server, per-mode "Always allow" toggles in webview | Copilot: `chat.tools.eligibleForAutoApproval`, `chat.tools.terminal.autoApprove` (regex map), per-tool **Always allow** in confirmation dialog (per workspace), `chat.tools.urls.autoApprove` with `approveRequest`/`approveResponse` granularity (Phase 4d §6) | ✅ | Copilot offers **finer granularity** (regex per terminal command, separate pre/post URL approval, org-policy `chat.tools.eligibleForAutoApproval` to *prevent* auto-approval). Net win. | +| G-11 | **Multi-profile vault automation** | Vault uses one VS Code profile (Default); symlink is single-target | `mcp.json` and `settings.json` are profile-scoped at `%APPDATA%\Code\User\profiles\\`; `prompts/` is global (Phase 4c §2 / Q-026) | 🟡 | Phase-8 PowerShell helper enumerates `profiles\*\` and re-points each. Owner: Phase 8. | +| G-12 | **Sub-agent return is a structured payload** | Roo `attempt_completion` has a defined `` shape that's consumed by the orchestrator | Copilot sub-agent returns the final assistant message as free-form text/markdown that becomes a tool result | 🟡 | Prompt the sub-agent to "return your output as a JSON block with these fields"; orchestrator parses. No structural guarantee. | +| G-13 | **Local model providers (per-key)** | Roo supports configuring per-provider keys (OpenAI, Anthropic, Bedrock, Ollama, etc.) | Copilot uses GitHub's model catalog only (no per-provider keys); third-party agent harness for Anthropic/OpenAI is a separate session type | 🟠 | If the user relies on a specific non-Copilot provider, the third-party-agent path is required. **Open Q for the user** — does the vault actually use a non-Copilot model today? Filed as **Q-030**. | +| G-14 | **Sandboxing on Windows** | n/a (Roo doesn't sandbox) | `chat.agent.sandbox.enabled` is **macOS/Linux only** (restated Phase 4c §9 / Phase 4d §6); MCP `sandboxEnabled` likewise ignored on Windows | 🟡 | No regression vs Roo; just a Windows-platform limitation that closes off one of Copilot's auto-approval shortcuts. | + +#### Copilot-only wins (for balance — things Copilot has that Roo lacks) + +| # | Capability | Why it matters | Citation | +|---|---|---|---| +| W-1 | **Native model selection across the GitHub model catalog** | No per-provider API key management; Copilot subscription covers GPT-5/Claude/Gemini/Grok/etc. via a single login | [Settings reference](https://code.visualstudio.com/docs/copilot/reference/copilot-settings) + Phase 4d §1 | +| W-2 | **`.agent.md` shipped via VSIX / Agent Plugins** | A single install delivers a vault-equivalent mode set; works alongside team-shared `.github/agents/` | Phase 4d §4 ([Agent plugins doc](https://code.visualstudio.com/docs/copilot/customization/agent-plugins)) | +| W-3 | **First-class `.prompt.md` slash commands** | Reusable, named one-shot prompts with frontmatter `agent:` binding — Roo has no equivalent | Phase 4b §1 | +| W-4 | **Built-in MCP discovery + `${input:…}` secret hygiene** | Workspace-committable `mcp.json` with first-run secret prompts → Windows Credential Manager; no gitignore split needed | Phase 4c §3 | +| W-5 | **Native AGENTS.md / CLAUDE.md / GEMINI.md cross-tool support** | Same instruction files work for Copilot, Claude Code, Gemini CLI, and Codex without duplication | Phase 4a §4 (Custom Instructions) | +| W-6 | **Cloud-agent runs (Copilot coding agent) using the same `.agent.md`** | Background coding sessions that produce PRs, sharing the local agent definitions | Phase 4d §10 + [docs.github.com — create custom agents](https://docs.github.com/en/copilot/how-tos/use-copilot-agents/coding-agent/create-custom-agents) | +| W-7 | **Parallel sub-agents + multi-model consensus** | A single coordinator can run reviews from several models in parallel and synthesize — Roo cannot do this at all | Phase 4d §8.4 | +| W-8 | **Checkpoints + Edit Previous Request + Fork Conversation** | Per-request file snapshots with one-click restore, plus conversation forking — Roo only has linear task history | Phase 4d §4 ([chat-checkpoints doc](https://code.visualstudio.com/docs/copilot/chat/chat-checkpoints)) | +| W-9 | **Per-tool URL approval with separate pre/post review** | `approveRequest` (don't send to a domain) and `approveResponse` (don't ingest from a domain) protect against prompt-injection on otherwise-trusted sites | Phase 4d §6 | +| W-10 | **Org-managed enterprise policies** | `chat.agent.enabled`, `chat.tools.global.autoApprove`, `chat.agent.networkFilter`, `chat.tools.eligibleForAutoApproval`, `chat.plugins.enabled` are device-management-policy-enforceable for Copilot Business / Enterprise | [agent-tools doc](https://code.visualstudio.com/docs/copilot/agents/agent-tools) | +| W-11 | **Single unified chat panel** | Vs Roo's separate panel — one place for Ask, Plan, Agent, custom agents, sub-agents, CLI hand-off, cloud hand-off | Phase 4d §5 | +| W-12 | **Hand-off between agent types (Local → CLI → Cloud)** | The same chat session can carry conversation history into a CLI worktree run or a cloud-agent PR session | [agents overview](https://code.visualstudio.com/docs/copilot/agents/overview) | + +#### Net assessment — feeds Phase 6 + +- **Blocker count:** 1 (`fileRegex` per-mode edit guard). +- **Major count:** 3 (per-mode rules folder, workspace-scoped tool sets, chat-history export, plus G-13 if the user relies on non-Copilot models). +- **Minor count:** ≥ 6 (sequential `new_task` parity, webview UI, 128-cap, sync, multi-profile, return-payload shape, sandbox-Windows). +- **Wins:** ≥ 12 covering model selection, plugin distribution, prompt files, cross-tool instructions, cloud-agent reuse, multi-agent orchestration, security policies, and unified UX. + +**Migration headline:** the gap profile **does not justify staying on Roo** purely on capability grounds — only the `fileRegex` blocker is a hard loss, and it has a workable (prose-instruction) mitigation. The wins, especially `.agent.md` cross-tool reuse and parallel sub-agents, materially expand the user's capability surface. This feeds directly into Phase 6's gap matrix and Phase 7's path recommendation. + +## Cross-links + +- [`00-plan.md`](00-plan.md) · [`50-copilot-cli-research.md`](50-copilot-cli-research.md) · [`60-gap-analysis.md`](60-gap-analysis.md) diff --git a/docs/investigation/roo-to-copilot/50-copilot-cli-research.md b/docs/investigation/roo-to-copilot/50-copilot-cli-research.md new file mode 100644 index 00000000000..94a5758c55e --- /dev/null +++ b/docs/investigation/roo-to-copilot/50-copilot-cli-research.md @@ -0,0 +1,1429 @@ +--- +phase: 5 +status: complete +owner: architect-subtask +last_updated: 2026-04-26 +sources: + - https://www.npmjs.com/package/@github/copilot + - https://www.npmjs.com/package/@github/copilot-sdk + - https://github.com/github/copilot-sdk + - https://github.com/github/copilot-sdk/blob/main/nodejs/README.md + - https://github.com/github/copilot-sdk/blob/main/docs/getting-started.md + - https://github.com/github/copilot-sdk/blob/main/CHANGELOG.md + - https://github.com/github/copilot-sdk/releases + - https://github.com/github/copilot-sdk/pull/272 + - https://github.com/github/copilot-sdk/pull/868 + - https://github.com/github/copilot-sdk/pull/881 + - https://docs.github.com/en/copilot/how-tos/copilot-sdk/sdk-getting-started + - https://github.blog/changelog/2026-04-02-copilot-sdk-in-public-preview/ + - https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-copilot-cli + - https://docs.github.com/en/copilot/how-tos/copilot-cli/install-copilot-cli + - https://docs.github.com/en/copilot/how-tos/copilot-cli/cli-best-practices + - https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically + - https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers + - https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-custom-instructions + - https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-custom-agents + - https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-skills + - https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-hooks + - https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-config-dir-reference + - https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-command-reference + - https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-programmatic-reference + - https://docs.github.com/en/copilot/reference/hooks-configuration + - https://docs.github.com/en/copilot/tutorials/copilot-cli-hooks + - https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference + - https://github.com/github/copilot-cli + - https://github.com/github/copilot-cli/issues/2392 + - https://github.com/github/copilot-cli/issues/2540 + - https://github.com/github/copilot-cli/issues/2893 + - https://github.com/github/copilot-cli/issues/2013 + - https://github.com/github/copilot-cli/issues/52 + - https://github.com/github/copilot-cli/issues/978 + - https://github.com/microsoft/vscode-copilot-release/issues/14131 + - https://github.com/anthropics/claude-code/issues/18737 + - https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills + - https://docs.github.com/en/copilot/concepts/agents/about-agent-skills + - https://docs.github.com/en/copilot/how-tos/copilot-sdk/use-copilot-sdk/custom-skills + - https://docs.github.com/en/copilot/how-tos/copilot-sdk/use-copilot-sdk/streaming-events + - https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/quickstart + - https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/automate-with-actions + - https://docs.github.com/en/copilot/how-tos/copilot-sdk/troubleshooting/sdk-and-cli-compatibility + - https://docs.github.com/en/copilot/how-tos/copilot-sdk/observability/opentelemetry + - https://agentskills.io/ +--- + + + +# Phase 5 — GitHub Copilot CLI Research + +> Parent plan: [`00-plan.md`](00-plan.md) · Index: [`README.md`](README.md) + +**What this file is for:** Mirror of [`40-copilot-chat-research.md`](40-copilot-chat-research.md) but for the **GitHub Copilot CLI** — specifically the standalone agentic CLI distributed as the npm package [`@github/copilot`](https://www.npmjs.com/package/@github/copilot), **not** the legacy `gh copilot` extension. Each section starts with a `Sources` subsection. + +## 0. Identity & Disambiguation + +### Sources + +- [`npmjs.com/package/@github/copilot`](https://www.npmjs.com/package/@github/copilot) — current CLI (v1.0.36 at access time). Accessed 2026-04-26. +- [`npmjs.com/package/@github/copilot-sdk`](https://www.npmjs.com/package/@github/copilot-sdk) — companion TypeScript SDK (v0.3.0). Accessed 2026-04-26. +- [`docs.github.com — about-copilot-cli`](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-copilot-cli) — official concepts overview. Accessed 2026-04-26. +- [`github.com/github/copilot-cli`](https://github.com/github/copilot-cli) — public issue/release tracker (binary is closed-source; only release artefacts and the SDK source are public). + +### Findings (2026-04-26) + +> ⚠️ **Naming-collision warning that supersedes the file's original brief.** The Phase-5 file template uses the phrase *"`gh copilot` and/or the standalone Copilot CLI agent"*. As of 2026-04-26 these are **two different products**: +> +> | Product | Package / Distribution | Binary | Status | +> |---|---|---|---| +> | **Copilot CLI** (this research) | `@github/copilot` (npm), `winget install GitHub.Copilot`, `brew install --cask github-copilot` | `copilot` | GA, agentic, default model Claude Sonnet 4.5 | +> | Legacy `gh-copilot` extension | `gh extension install github/gh-copilot` | `gh copilot suggest` / `gh copilot explain` | Maintenance-only; non-agentic; *not* the migration target | +> +> All findings below refer to the **standalone agentic CLI** (`@github/copilot`). Where this document says "the CLI" without qualification, it means `@github/copilot` v1.0.36. + +The CLI is a **closed-source Node application** distributed via npm; the public [`github/copilot-cli`](https://github.com/github/copilot-cli) repo carries release notes and an issue tracker but no source. The companion **SDK** [`@github/copilot-sdk`](https://www.npmjs.com/package/@github/copilot-sdk) is open-source (MIT) TypeScript and ships a programmatic embedding surface (`CopilotClient`, `CopilotSession`, `defineTool`, …); see § 5 below. + +The CLI implements the **Agent Client Protocol (ACP)** as a server (`copilot acp`) so editors and other clients can drive it as a backend agent. + +--- + +## 1. Install & Authentication + +### Sources + +- [`docs.github.com — install-copilot-cli`](https://docs.github.com/en/copilot/how-tos/copilot-cli/install-copilot-cli). Accessed 2026-04-26. +- [`npmjs.com/package/@github/copilot`](https://www.npmjs.com/package/@github/copilot) — Install section + system requirements. Accessed 2026-04-26. +- [`docs.github.com — cli-config-dir-reference`](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-config-dir-reference) — `COPILOT_HOME` semantics, OS-specific paths. + +### Findings (2026-04-26) + +#### 1.1 System requirements + +- **Node.js ≥ 22** (per the CLI's npm page; the SDK README softens this to ≥ 18 but the bundled CLI hard-requires 22+). +- **Windows: PowerShell v6 or newer** (`pwsh`, not the in-box Windows PowerShell 5.1). The CLI shells out to `pwsh -Command …` for its `powershell` tool family; absence of `pwsh` results in tool-call failures even though the CLI itself launches. +- **macOS / Linux: bash or zsh** for the `bash` tool family. +- A **GitHub Copilot subscription** — Pro, Pro+, Business, or Enterprise. Free tier is **not** supported. + +#### 1.2 Install methods (Windows-first) + +| Method | Command | Notes | +|---|---|---| +| **winget** (recommended on Windows 11) | `winget install GitHub.Copilot` | Installs `copilot.exe`; auto-handles PATH. | +| **npm (global)** | `npm install -g @github/copilot` | Requires Node ≥ 22 already on PATH; portable across OSes. | +| **GitHub release download** | Download platform binary from [`github.com/github/copilot-cli/releases`](https://github.com/github/copilot-cli/releases) | No package-manager dependency. | +| **macOS** | `brew install --cask github-copilot` | Cask, not formula. | +| **Linux** | `curl -fsSL https://aka.ms/install-copilot-cli.sh | sh` | Auto-install script. | + +Verify with `copilot --version` (prints CLI + bundled SDK versions and Node runtime). + +#### 1.3 Authentication + +The CLI supports three auth flows, evaluated in this **precedence order** (first non-empty wins): + +1. **`COPILOT_GITHUB_TOKEN`** environment variable. +2. **`GH_TOKEN`** environment variable (shared with `gh` CLI). +3. **`GITHUB_TOKEN`** environment variable (shared with GitHub Actions). +4. **OAuth device flow** via the interactive `/login` slash command — opens the user's default browser, prompts for the device code, stores the resulting token in the **OS keychain** (Windows Credential Manager on Win11; macOS Keychain; libsecret on Linux). Set `storeTokenPlaintext: true` in `~/.copilot/settings.json` to fall back to a plaintext token file (not recommended). + +**Token-type requirements:** +- For PAT-based auth (env-var route), tokens must be **fine-grained PATs** with the **Copilot Requests** permission. Classic `ghp_…` PATs are **not accepted**. +- For GitHub Enterprise Cloud with Data Residency, set `--host` or `GH_HOST` / `COPILOT_GH_HOST` (e.g., `--host github.acme.ghe.com`). + +Logout: `/logout` slash command (clears keychain entry); env-var-based auth ignores `/logout`. + +#### 1.4 Subscription tiers — feature gating + +All paid Copilot tiers can run the CLI. Differences observed: +- **Pro** — single-user; default models (Claude Sonnet 4.5, GPT-5, Claude Opus 4.x); standard request quota. +- **Pro+** — adds higher-tier models (Opus 4.7) and increased monthly request budget. +- **Business / Enterprise** — adds **org policies** (model allowlists, MCP server allowlists, disable-hooks toggles); these are enforced fail-closed by the CLI. + +--- + +## 2. Storage Locations (Windows) + +### Sources + +- [`docs.github.com — cli-config-dir-reference`](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-config-dir-reference). Accessed 2026-04-26. +- [`npmjs.com/package/@github/copilot`](https://www.npmjs.com/package/@github/copilot) — "Configuration directory" section. + +### Findings (2026-04-26) + +#### 2.1 Path layout + +| Purpose | Default (Windows 11) | Override mechanism | +|---|---|---| +| **Config root** | `%USERPROFILE%\.copilot\` | `COPILOT_HOME` env var **or** `--config-dir ` CLI flag (per-invocation) | +| **Cache** (model responses, downloaded resources) | `%LOCALAPPDATA%\copilot\` | not user-configurable | +| Keychain entry | Windows Credential Manager: target `github.com:copilot-cli` | n/a | +| Logs | `%USERPROFILE%\.copilot\logs\` | follows `COPILOT_HOME` | + +**`COPILOT_HOME` redirects every config sub-path** (settings, agents, skills, instructions, hooks, MCP, sessions). This is the integration hook for the user's vault — see § 6.4. + +#### 2.2 Contents of `~/.copilot/` + +```text +~/.copilot/ +├── settings.json ← global settings (cascaded by repo + local) +├── copilot-instructions.md ← always-on global instructions +├── instructions/ ← *.instructions.md modular instructions +│ └── *.instructions.md +├── agents/ ← user-scope custom agents (.agent.md or .md) +│ └── .agent.md +├── skills/ ← user-scope skills (each in own subdir w/ SKILL.md) +│ └── / +│ └── SKILL.md +├── hooks/ ← user-scope hooks.json or hooks.d/*.json +│ └── hooks.json +├── mcp-config.json ← user-scope MCP servers +├── plugins/ ← installed plugins +├── session-state/ ← per-session event logs and checkpoints +│ └── / +│ ├── events.jsonl +│ ├── workspace.yaml +│ ├── plan.md +│ ├── checkpoints/ +│ └── files/ +├── session-store.db ← SQLite FTS5 index for /resume search +├── logs/ +└── auth/ ← (only if storeTokenPlaintext: true) +``` + +#### 2.3 Settings cascade + +```text +~/.copilot/settings.json (user-global) + └─► .github/copilot/settings.json (repository, committed) + └─► .github/copilot/settings.local.json (per-clone, gitignored) +``` + +Each subsequent layer **deep-merges** over the previous. The repository layer only honours a small allowlist of keys: `companyAnnouncements`, `disableAllHooks`, `enabledPlugins`, `extraKnownMarketplaces`, `hooks`, `mergeStrategy`. All other repo-level keys are ignored (security guard against arbitrary settings injection from cloned repos). + +A **legacy `config.json`** in the same locations is auto-migrated to `settings.json` on first run. + +#### 2.4 What's safe to delete + +| Path | Safe to delete? | Effect | +|---|---|---| +| `session-state//` | ✅ | Forgets that session; `--resume` will not find it. | +| `session-store.db` | ✅ | Index is rebuilt from `session-state/` on next launch. | +| `logs/` | ✅ | No effect. | +| `cache` (`%LOCALAPPDATA%\copilot\`) | ✅ | Re-downloads on next use. | +| `settings.json`, `mcp-config.json`, `agents/`, `skills/`, `instructions/` | ❌ | Loses user customisation. | +| `auth/` (or keychain entry) | ⚠️ | Forces re-login. | + +--- + +## 3. Agent Loop + +### Sources + +- [`docs.github.com — about-copilot-cli`](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-copilot-cli) — modes, infinite sessions, BYOK. Accessed 2026-04-26. +- [`docs.github.com — cli-best-practices`](https://docs.github.com/en/copilot/how-tos/copilot-cli/cli-best-practices). Accessed 2026-04-26. +- [`docs.github.com — cli-command-reference`](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-command-reference). Accessed 2026-04-26. +- [`docs.github.com — run-cli-programmatically`](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically). Accessed 2026-04-26. + +### Findings (2026-04-26) + +#### 3.1 Modes (Standard / Plan / Autopilot) + +The CLI exposes **three execution modes**, cycled with **Shift+Tab** in interactive mode or pinned via `--mode=plan|interactive|autopilot`: + +| Mode | Approval policy | Iteration cap | Use case | +|---|---|---|---| +| **Standard** (default) | Prompts on every tool call requiring `write` / `shell` / network | Unbounded (interactive) | Human-in-the-loop coding | +| **Plan** | Read-only; tool calls that would mutate state are converted to plan entries | Single planning pass | Pre-flight design; `/plan` slash command equivalent | +| **Autopilot** | Auto-approves anything matching the active allowlist; **does not** auto-approve outside it | Capped by `--max-autopilot-continues` (default ~25) | CI / scripted runs | + +**Plan mode** writes a structured `plan.md` to `session-state//plan.md` and terminates without executing it. The user (or a follow-up `--continue`) executes it. + +**Autopilot** + `/fleet` enables parallel sub-task fan-out. + +#### 3.2 The control loop (per turn) + +1. Read user prompt (interactive) or `--prompt` (programmatic). +2. Run **`userPromptSubmitted`** hooks (can mutate or block the prompt). +3. Compose system prompt from the cascade (§ 4) plus the active agent's body (§ 6). +4. LLM produces a thinking → tool-call → result cycle: + - For each tool call: check **permission** (allow/deny/prompt) per the `Kind(argument)` pattern. + - Run **`preToolUse`** hooks (HTTPS-required if `allowedEnvVars` is non-empty; can deny). + - Execute tool. + - Run **`postToolUse`** hooks (or `postToolUseFailure` on error). +5. Repeat 4 until the model emits a final answer or hits an iteration / token limit. +6. Run **`agentStop`** hook. +7. **Auto-compact** the conversation if context usage ≥ 95% (configurable); else persist new events to `session-state//events.jsonl`. + +#### 3.3 Permission system + +Permissions are matched as `Kind(argument)` patterns: + +| Kind | Examples | Notes | +|---|---|---| +| `shell` | `shell(git status)`, `shell(git:*)`, `shell(npm test)` | `:*` matches `git ` plus any args (stem with trailing space). | +| `write` | `write`, `write(./src/**)`, `write(/tmp/**)` | Glob over absolute or workspace-relative paths. | +| `read` | same as `write` | Rarely needed (reads default-allowed in standard mode). | +| `url` | `url(https://api.github.com/**)`, `url(github.com)` | Matched on the fetch target. | +| `memory` | `memory` | The `memory` built-in tool. | +| `` | `MyMcp(*)`, `Trello(create_card)` | One scope per registered MCP server; tool-name level filtering. | + +Allow/deny lists are settable at: (a) `settings.json` (`allowedTools` / `deniedTools` arrays), (b) per-invocation `--allow-tool='shell(git:*)'` / `--deny-tool='shell(git push)'`, (c) the broad escape hatches `--allow-all-tools`, `--allow-all-paths`, `--allow-all-urls`, `--yolo` (== all three). + +**Deny wins over allow** when both match. + +#### 3.4 Programmatic / headless invocation + +```cmd +copilot -p "summarize CHANGELOG.md" --allow-tool="read" --no-ask-user --output-format=json +``` + +Key flags for scripting: + +| Flag | Effect | +|---|---| +| `-p, --prompt ` | One-shot prompt; CLI exits after the model completes. | +| `-s, --silent` | Suppress all chrome; emit only the final answer (or JSONL if combined with `--output-format`). | +| `--no-ask-user` | Disable the `ask_user` interactive tool (model can't pause for input). | +| `--allow-tool=PATTERN` | Repeatable; expand allowed-tool set. | +| `--deny-tool=PATTERN` | Repeatable; expand denied-tool set. | +| `--allow-all-tools` | ⚠️ Allow every tool, including `shell(*)`. | +| `--allow-all-paths` / `--allow-all-urls` | Looser scope variants. | +| `--yolo` | Equivalent to all three "all" flags. | +| `--mode=plan|interactive|autopilot` | Pin a mode. | +| `--max-autopilot-continues=N` | Cap auto-iterations (default ~25). | +| `--output-format=text|json` | `json` emits **JSONL** events (one JSON object per line). | +| `--share=` / `--share-gist` | Persist a shareable transcript. | +| `--config-dir=` | Per-invocation `COPILOT_HOME` override. | +| `--additional-mcp-config=JSON|@file` | Session-only MCP server definitions. | +| `--add-dir=` | Add a workspace root (multi-repo). | +| `--agent=` | Boot the session under a specific custom agent. | +| `--model=` | Override default (Claude Sonnet 4.5). Special: `auto`, `claude-opus-4.5`, `claude-opus-4.7`, `gpt-5`, `gpt-5.2-codex`. | + +Exit codes: `0` success; non-zero on tool-permission denial (with `--no-ask-user`), auth failure, or context-cap exceeded with no producible answer. + +#### 3.5 Sessions, resume, infinite context + +- Every session gets a UUID and is stored under `session-state//`. +- **Auto-compaction** at ~95% context preserves a summary + recent events; the running task continues without interruption ("infinite sessions"). +- Resume: + - `copilot --continue` — resumes the **most recent session in the current cwd**. + - `copilot --resume` — interactive picker over all sessions. + - `copilot --resume ` — non-interactive resume. + - In-session: `/resume`, `/rename `, `/session`. +- The `session-store.db` SQLite FTS5 index powers free-text search across events and plan files. + +#### 3.6 Built-in tool surface + +Tools available to the model by default (subject to permission gating): + +| Group | Tools | +|---|---| +| **Shell** | `bash`, `bash_list`, `bash_read`, `bash_stop`, `bash_write` (POSIX); `powershell`, `powershell_list`, `powershell_read`, `powershell_stop`, `powershell_write` (Windows) | +| **Files** | `apply_patch`, `create`, `edit`, `view`, `glob`, `grep` (rg-backed), `show_file` *(experimental)* | +| **Task delegation** | `task` (dispatch a sub-agent), `list_agents`, `read_agent` | +| **User interaction** | `ask_user` (suppressed by `--no-ask-user`) | +| **Web / network** | `web_fetch` (subject to `url(...)` permission and the SSRF allowlist) | +| **Skills** | `skill` (invoke a registered skill) | +| **Memory** | `memory` (write/read/delete persistent notes; gated by the `memory` permission) | +| **MCP** | One synthetic tool per MCP-server tool, namespaced as `()` | + +#### 3.7 Comparison to Roo's loop + +| Axis | Roo-Code | Copilot CLI | +|---|---|---| +| Default loop shape | Sequential ReAct + `new_task` boomerang | ReAct + `task` sub-agent dispatch (parallel-capable) | +| Per-mode tool restriction | `groups` array + `fileRegex` | `.agent.md` `tools:` array + `--allow-tool` / `--deny-tool` (no `fileRegex` equivalent) | +| Per-mode MCP allowlist | `allowedMcpServers: [...]` | `tools: ["MyServer/*"]` (or `--allow-tool='MyServer(*)'`) | +| Iteration cap | None enforced; relies on prose | `--max-autopilot-continues` (autopilot only) | +| Auto-compaction | None (manual `/clear`-equivalent in webview) | Yes, at ~95% context, automatic | +| Headless / scriptable | Indirect (VS Code ext only) | First-class (`-p`, exit codes, JSONL) | +| Approval UX | Per-tool prompt in webview | Per-tool prompt in TTY; allow/deny lists; modes | + +--- + +## 4. Custom Instructions + +### Sources + +- [`docs.github.com — use-custom-instructions`](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-custom-instructions). Accessed 2026-04-26. +- [`docs.github.com — cli-config-dir-reference`](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-config-dir-reference) — file-discovery rules. +- [`docs.github.com — cli-best-practices`](https://docs.github.com/en/copilot/how-tos/copilot-cli/cli-best-practices) — system-prompt customisation modes. + +### Findings (2026-04-26) + +#### 4.1 Discovery cascade + +The CLI loads instructions from **all** of these locations and **concatenates** them (no priority fallback — every match is included): + +| Scope | Path | Notes | +|---|---|---| +| User-global, primary | `~/.copilot/copilot-instructions.md` | Always-on across every project. | +| User-global, modular | `~/.copilot/instructions/*.instructions.md` | Each file may declare an `applyTo:` glob in YAML frontmatter. | +| Repository, primary | `.github/copilot-instructions.md` | Cross-tool standard (Copilot Chat reads the same file). | +| Repository, modular | `.github/instructions/**/*.instructions.md` | Same `applyTo:` semantics. | +| Workspace root | `AGENTS.md` | The cross-tool ["AGENTS.md" convention](https://agents.md/). | +| Workspace root (compat) | `Copilot.md`, `GEMINI.md`, `CODEX.md`, `CLAUDE.md` | Read iff present, for cross-tool portability. | + +#### 4.2 System-prompt customisation modes + +The `systemPrompt` setting in `settings.json` controls how user instructions interact with the built-in system prompt: + +| Mode | Behaviour | +|---|---| +| `default` | User instructions are **appended** to the built-in prompt. | +| `customize` | User can **override individual sections** by name: `identity`, `tone`, `tool_efficiency`, `environment_context`, `code_change_rules`, `guidelines`, `safety`, `tool_instructions`, `custom_instructions`, `last_instructions`. Unspecified sections fall through to the default. | +| `replace` | Full override of the system prompt (advanced; risk of breaking tool calling). | + +#### 4.3 Implications for the vault + +- **The vault's per-mode rules folders (`.roo/rules-/`) have no first-class CLI equivalent.** Same gap as Copilot Chat (Q-018). Recommended pattern: inline rules into each `.agent.md` body (§ 6) or compose via an `applyTo:`-globbed `.instructions.md`. +- **Vault-wide global rules survive cleanly** by symlinking `~/.copilot/copilot-instructions.md` → `/global-settings/copilot-instructions.md` (mirrors the Roo `~/.roo/rules/` pattern). +- **`AGENTS.md` is shared with Copilot Chat** — single source of truth for cross-tool rules. + +--- + +## 5. Custom Agents (`--agent`, `.agent.md`) + +### Sources + +- [`docs.github.com — use-custom-agents`](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-custom-agents). Accessed 2026-04-26. +- [`docs.github.com — cli-command-reference`](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-command-reference) — `/agent` slash command, built-in agent list. +- [`npmjs.com/package/@github/copilot-sdk`](https://www.npmjs.com/package/@github/copilot-sdk) — SDK-side agent registration. + +### Findings (2026-04-26) + +#### 5.1 Discovery & precedence + +The CLI scans for agent files in this order (later overrides earlier when names collide): + +1. **Plugin agents** (lowest priority) — bundled by installed plugins. +2. **User agents** — `~/.copilot/agents/*.agent.md` (and `*.md`); plus `~/.claude/agents/*.md` (Claude format). +3. **Project agents** (highest priority) — `.github/agents/*.agent.md`; plus `.claude/agents/*.md`. + +Built-in agents (always available, can be overridden by name): `code-review`, `configure-copilot`, `explore`, `general-purpose`, `research`, `rubber-duck`, `task`. + +Selection: `copilot --agent=` boots the session under that agent; `/agent ` switches mid-session; `task(agent="", prompt="…")` dispatches a sub-agent. Default sub-agent depth limit = 6; default concurrency = 32. + +#### 5.2 Frontmatter schema (CLI flavour) + +```yaml +--- +name: code-reviewer # optional; defaults to filename +description: Reviews diffs and flags issues # required +model: claude-opus-4.7 # optional; falls back to session model +tools: [view, grep, glob, web_fetch, github-mcp-server/*] # optional allowlist +mcp-servers: [github-mcp-server, my-internal-mcp] # optional MCP allowlist +infer: true # optional; legacy — replaced by user-invocable +--- + +# Body — Markdown system prompt prepended to user turns +You are a senior code reviewer. ... +``` + +Supported fields (per CLI docs): `description` (required), `name`, `model`, `tools`, `mcp-servers`, `infer`. **The CLI flavour is a strict subset of the VS Code `.agent.md` schema** (no `agents:`, `handoffs:`, `target:`, `argument-hint:`, `user-invocable:`, `disable-model-invocation:` — those are VS Code extensions). Dual-target authoring is therefore safe: a CLI-valid `.agent.md` is also a valid VS Code agent (the extra fields are simply unused). + +#### 5.3 Slash commands relevant to agents + +`/agent`, `/agent `, `/delegate`, `/fleet`, `/list-agents`, `/init` (scaffold a new agent in `.github/agents/`). + +#### 5.4 Mapping the vault's 17 modes onto CLI agents + +Each entry in `/global-settings/custom_modes.yaml` (slug + name + roleDefinition + customInstructions + groups + allowedMcpServers) maps mechanically: + +| `.roomodes` field | `.agent.md` equivalent | Notes | +|---|---|---| +| `slug` | filename `.agent.md` | | +| `name` | `name:` frontmatter | | +| `roleDefinition` + `customInstructions` | Body of the `.agent.md` | Concatenated. | +| `groups` (`read`, `edit`, `command`, `mcp`, `browser`) | `tools:` array | `read` → `view`, `glob`, `grep`. `edit` → `apply_patch`, `create`, `edit`. `command` → `bash`/`powershell` family. `browser` → `web_fetch`. `mcp` → enumerate `/*`. | +| `groups[].fileRegex` | **No equivalent** | Lossy; must be enforced via prose ("only edit files matching …") or a `preToolUse` hook on `write`. (Same as Chat G-1.) | +| `allowedMcpServers: [...]` | `mcp-servers:` + `tools: ["/*", ...]` | `[]` means "no MCP" → omit all server entries. | +| `whenToUse` | Not represented | Discoverability is via `/agent` picker only. | + +--- + +## 6. Squad Cross-Reference + +### Sources + +- [`30-squad-inventory.md`](30-squad-inventory.md) — Phase-3 Squad findings. +- [`../squad/.copilot/mcp-config.json`](../../../../squad/.copilot/mcp-config.json) — actual squad MCP config. +- [`../squad/packages/squad-sdk/package.json`](../../../../squad/packages/squad-sdk/package.json) — confirms `@github/copilot-sdk` dependency. +- [`../squad/README.md`](../../../../squad/README.md) — invocation pattern `copilot --agent squad`. + +### Findings (2026-04-26) + +Squad does not replace the CLI — it **drives** the CLI via the SDK and registers itself as a custom agent (`copilot --agent squad`). Concrete observations from the squad workspace: + +#### 6.1 Squad's `.copilot/` layout + +```text +../squad/.copilot/ +├── mcp-config.json ← project-scoped MCP servers (CLI honours this for the squad workspace) +└── skills/ ← project-scoped skills +``` + +> ⚠️ **Non-standard MCP location.** The CLI documentation establishes `.github/mcp.json` and the user-global `~/.copilot/mcp-config.json` as the canonical project / user MCP locations. Squad uses **`.copilot/mcp-config.json` at the project root** — which is the **user-format file in a project-scope directory**. The CLI does load this when launched from the squad workspace because `COPILOT_HOME` is implicitly `.copilot/` for that project (squad's launcher sets it). This is a squad-specific convention, not a CLI default. **New question opened (Q-031).** + +The squad sample `mcp-config.json` confirms the user-format MCP schema (`mcpServers` map; per-server `command`/`args`/`env` with `${VAR}` substitution): + +```json +{ + "mcpServers": { + "EXAMPLE-trello": { + "command": "npx", + "args": ["-y", "@trello/mcp-server"], + "env": { + "TRELLO_API_KEY": "${TRELLO_API_KEY}", + "TRELLO_TOKEN": "${TRELLO_TOKEN}" + } + } + } +} +``` + +`${VAR}` is substituted from the **process environment** (not from a `.env` file unless the squad launcher loads one) — analogous to VS Code Copilot Chat's `${input:…}` but **without** the keychain-prompt UX. Secrets must therefore be set in the parent shell or in `.copilot/.env` (gitignored). + +#### 6.2 Squad ↔ `vscode.lm` (resolves Q-010) + +Squad depends only on `@github/copilot-sdk` ([`../squad/packages/squad-sdk/package.json`](../../../../squad/packages/squad-sdk/package.json)). It has **no** `vscode.lm`, `vscode`, or `@vscode/*` dependency. Squad is **strictly external CLI-driven** and cannot be embedded in a VS Code extension as-is. + +#### 6.3 What squad adds on top of the CLI + +| CLI primitive | Squad layer on top | +|---|---| +| `task` sub-agent dispatch | `fan-out`, `wave-dispatch`, `fleet-dispatch` parallel orchestrators | +| `--continue` / `--resume` | Persistent named agents with markdown state in `.squad/` | +| `--prompt` one-shot | Ralph watch-mode (file-watcher → re-prompt loop) | +| `~/.copilot/agents/` user agents | Casting registry (named-agent factory in `.squad/casting.md`) | + +#### 6.4 Vault integration sketch + +The vault's symlink-and-commit pattern can be mirrored on the CLI side via `COPILOT_HOME`: + +```powershell +# Per-project bootstrap (added to setup-vault.ps1) +$projectRoot = "C:\git\" +$vaultCli = "C:\git\roo-vault\global-settings\copilot" +[Environment]::SetEnvironmentVariable("COPILOT_HOME", $vaultCli, "User") + +# Or per-invocation: +copilot --config-dir "C:\git\roo-vault\global-settings\copilot" --agent code "$@" +``` + +This makes the vault's `agents/`, `instructions/`, `skills/`, `hooks/`, and `mcp-config.json` portable across machines without the per-profile-id complexity that VS Code Copilot Chat requires (Q-026). + +--- + +## 7. SDK (`@github/copilot-sdk`) — Full Export Catalogue (Phase 5b-ii-B-1) + +### Sources + +- [`npmjs.com/package/@github/copilot-sdk`](https://www.npmjs.com/package/@github/copilot-sdk) — package readme + API reference (v0.3.0 at access). Accessed 2026-04-26. +- [`github.com/github/copilot-sdk`](https://github.com/github/copilot-sdk) — public monorepo (Node, Go, .NET, Java, Python). Accessed 2026-04-26. +- [`github/copilot-sdk/blob/main/nodejs/README.md`](https://github.com/github/copilot-sdk/blob/main/nodejs/README.md) — canonical Node.js API surface. Accessed 2026-04-26. +- [`github/copilot-sdk/blob/main/docs/getting-started.md`](https://github.com/github/copilot-sdk/blob/main/docs/getting-started.md) — quickstart + custom-tool walkthrough. Accessed 2026-04-26. +- [`github/copilot-sdk/blob/main/CHANGELOG.md`](https://github.com/github/copilot-sdk/blob/main/CHANGELOG.md) — versioning & breaking-change history. Accessed 2026-04-26. +- [`github/copilot-sdk/releases`](https://github.com/github/copilot-sdk/releases) — release notes. Accessed 2026-04-26. +- [`docs.github.com — sdk-getting-started`](https://docs.github.com/en/copilot/how-tos/copilot-sdk/sdk-getting-started). Accessed 2026-04-26. +- [`github.blog — Copilot SDK in public preview (2026-04-02)`](https://github.blog/changelog/2026-04-02-copilot-sdk-in-public-preview/). Accessed 2026-04-26. +- [`docs.github.com — sdk-and-cli-compatibility`](https://docs.github.com/en/copilot/how-tos/copilot-sdk/troubleshooting/sdk-and-cli-compatibility). Accessed 2026-04-26. +- Ground-truth Squad source: [`../squad/packages/squad-sdk/src/adapter/client.ts`](../squad/packages/squad-sdk/src/adapter/client.ts), [`../squad/packages/squad-sdk/src/adapter/types.ts`](../squad/packages/squad-sdk/src/adapter/types.ts), [`../squad/packages/squad-sdk/src/build/bundle.ts`](../squad/packages/squad-sdk/src/build/bundle.ts), [`../squad/packages/squad-cli/src/cli-entry.ts`](../squad/packages/squad-cli/src/cli-entry.ts). + +### 7.1 Package identity + +| Attribute | Value | Source | +|---|---|---| +| npm name | `@github/copilot-sdk` | npm page | +| Latest version | **v0.3.0** (54 versions; 134 dependents at access) | npm page | +| License | **MIT** | npm "License" panel + `nodejs/README.md` | +| Stability tier | **Public preview / alpha (`0.x`)** — *"While in public preview, minor breaking changes may still occur between releases"* (sister `copilot-sdk-java` releases note, mirrored across all language SDKs in the monorepo) | Java release page; reinforced by GA blog of 2026-04-02 | +| Node requirement | Node **20+** (typical for the 0.x line; Node 24+ has a known broken-ESM-import workaround patched at runtime by Squad — see [`squad-cli/src/cli-entry.ts`](../squad/packages/squad-cli/src/cli-entry.ts) lines 25–28) | Squad cli-entry comment + GitHub issues | +| Install | `npm install @github/copilot-sdk` (auto-installs the underlying CLI on first `client.start()` unless `cliPath`/`cliUrl` is set) | docs.github.com quickstart | +| Languages | Node.js, Go, .NET, Java, Python (sibling packages in the same monorepo) | repo top-level | +| Runtime deps | 3 (lean) — `vscode-jsonrpc` is the load-bearing one (JSON-RPC transport to the CLI subprocess) | npm "Dependencies" tab | + +> *"The Copilot SDK provides language-specific wrappers for programmatic access to the GitHub Copilot CLI."* — towardsai.net summary, corroborating that the SDK **does not contain a model client of its own** — it speaks JSON-RPC to a spawned (or remote) CLI process. + +### 7.2 Public exports — Node.js surface + +Sourced from the [npm readme](https://www.npmjs.com/package/@github/copilot-sdk) and [`nodejs/README.md`](https://github.com/github/copilot-sdk/blob/main/nodejs/README.md). "✅ doc" = explicitly named in the README API reference; "🟡 inferred" = visible in Squad's import/usage but not headline-documented. + +#### Session / agent loop + +| Export | Kind | Purpose | Status | +|---|---|---|---| +| `CopilotClient` | class | Top-level client; spawns or connects to the CLI. Constructor: `{ cliPath?, cliArgs?, cliUrl?, cwd?, port?, useStdio?, logLevel?, autoStart?, env?, githubToken?, useLoggedInUser?, telemetry? }`. | ✅ doc | +| `CopilotSession` | class | Per-conversation driver returned by `createSession`. Properties `sessionId`, `workspacePath`, `capabilities`, `ui`. | ✅ doc | +| `client.start()` / `stop()` / `forceStop()` | method | Lifecycle (`start: Promise`, `stop: Promise`, `forceStop: Promise`). | ✅ doc | +| `client.createSession(config)` | method | Required `onPermissionRequest`; optional `model`, `reasoningEffort` (`low|medium|high|xhigh`), `tools`, `systemMessage`, `infiniteSessions`, `provider`, `hooks`, `onUserInputRequest`, `onElicitationRequest`, `sessionId`. | ✅ doc | +| `client.resumeSession(id, config?)` | method | Resume by id; `workspacePath` populated when infinite sessions enabled. | ✅ doc | +| `client.listSessions(filter?)` | method | Returns `SessionMetadata[]` (`sessionId`, `startTime`, `modifiedTime`, `summary`, `isRemote`, `context`). | ✅ doc | +| `client.deleteSession(id)` / `getForegroundSessionId()` / `setForegroundSessionId(id)` | method | Session admin. | ✅ doc | +| `client.getLastSessionId()` / `getStatus()` / `getAuthStatus()` / `listModels()` / `ping(msg?)` | method | CLI introspection. | ✅ doc (used by Squad's [`adapter/client.ts:639–748`](../squad/packages/squad-sdk/src/adapter/client.ts:639)) | +| `session.send(opts)` / `sendAndWait(opts, timeout?)` | method | Streaming vs. await-final. | ✅ doc | +| `session.abort()` / `disconnect()` / `getMessages()` | method | Session control + replay. | ✅ doc | +| `session.destroy()` | method | Deprecated alias for `disconnect()`. | ✅ doc (deprecated) | + +#### Tools (custom + built-in) + +| Export | Purpose | +|---|---| +| `defineTool(name, { description, parameters: ZodSchema, handler })` | Type-safe custom tool registration. Tools become available to the model and route back to your handler when invoked. | +| `Tool` (type) | Runtime type returned by `defineTool`; passed in `createSession({ tools: [...] })`. | +| Per-tool `skipPermission` / "Overriding built-in tools" | Documented patterns (named sections in the readme) that let you replace `read`/`write`/`shell`/etc. with your own handler, or pre-approve specific tools. | + +> *"You can let the CLI call back into your process when the model needs capabilities you own."* — [`nodejs/README.md`](https://github.com/github/copilot-sdk/blob/main/nodejs/README.md) "Tools" section. + +#### Hooks (programmatic — orthogonal to file-based hooks of § 10) + +| Export | Purpose | +|---|---| +| `SessionHooks` (config) passed via `createSession({ hooks })` | In-process hooks (TypeScript callbacks, **not** spawned commands). | +| `onPreToolUse(input)` → `{ permissionDecision: "allow"\|"deny"\|"ask", modifiedArgs?, additionalContext? }` | Same semantics as file-based `preToolUse` but runs in your Node process. | +| `onPostToolUse(input, invocation)` → `{ additionalContext? }` | Result post-processing. | +| `onUserPromptSubmitted` / `onSessionStart` / `onSessionEnd` / `onErrorOccurred` | Lifecycle callbacks (parity list with file-based hooks). | + +> Direct quote from the readme: +> *"Available hooks: `onPreToolUse` … `onPostToolUse` … `onUserPromptSubmitted` … `onSessionStart` … `onSessionEnd` … `onErrorOccurred`."* + +#### MCP + +| Export | Purpose | +|---|---| +| MCP servers configured **per-session** via `createSession({ mcpServers: {...} })` (not via `mcp-config.json`) | The SDK passes MCP server definitions through to the CLI subprocess. | +| `kind: "mcp"` permission requests | `onPermissionRequest` is fired for MCP tool calls; handler returns `{ kind: "approved" \| "denied" }`. | + +> *"📖 Full MCP documentation → docs/features/mcp.md — Learn about local vs remote servers, all configuration options, and troubleshooting."* — getting-started.md. + +⚠️ uncertain — Q-045: explicit programmatic `addMcpServer(...)` helper not visible in the README API reference; configuration appears to be declarative only via session config. + +#### Model providers / BYOK + +| Export | Purpose | +|---|---| +| `ProviderConfig` (type) | Passed to `createSession({ provider })`. Fields: `type?: "openai" \| "azure" \| "anthropic"` (default `"openai"`), `baseUrl`, `apiKey`, plus type-specific extras. **You must specify `model` explicitly when using a custom provider.** | +| Env-var fallback | `COPILOT_PROVIDER_BASE_URL` / `COPILOT_PROVIDER_TYPE` / `COPILOT_PROVIDER_API_KEY` / `COPILOT_MODEL` (resolves Q-030 for the CLI path; SDK inherits same env). | + +> *"The SDK supports custom OpenAI-compatible API providers (BYOK - Bring Your Own Key), including local providers like Ollama. When using a custom provider, you must specify the `model` explicitly."* — readme. + +#### Events / streaming + +| Export | Purpose | +|---|---| +| `session.on(eventType, handler)` / `session.on(handler)` | Typed event filtering (added in [PR #272](https://github.com/github/copilot-sdk/pull/272), Node SDK). Returns an unsubscribe `() => void` (per Squad's [`adapter/client.ts:116`](../squad/packages/squad-sdk/src/adapter/client.ts:116)). | +| `client.on(eventType, handler)` / `client.on(handler)` | Client-level lifecycle (`SessionLifecycleEventType` / `SessionLifecycleHandler`). | +| Event types | Dotted-namespace strings: `assistant.message_delta`, `assistant.message`, `assistant.usage`, `assistant.reasoning_delta`, `assistant.reasoning`, `assistant.turn_start`, `assistant.turn_end`, `assistant.intent`, `session.idle`, `session.error`, plus `tool.execution_start`, `session.shutdown` (added per [PR #868](https://github.com/github/copilot-sdk/pull/868)). | +| `UnknownSessionEvent` | Forward-compat wrapper for unknown event types from newer CLI versions ([PR #881](https://github.com/github/copilot-sdk/pull/881) for .NET; same pattern across SDKs). | +| `AssistantMessageEvent` | Returned by `sendAndWait`. | + +#### Auth, UI, telemetry, error handling + +| Export | Purpose | +|---|---| +| `useLoggedInUser` / `githubToken` | Two auth paths (CLI's logged-in user vs. explicit token). | +| `PermissionHandler` / `PermissionRequest` / `PermissionRequestResult` | Per-tool gating. `request.kind` ∈ `shell \| write \| read \| mcp \| custom-tool \| url \| memory \| hook` (extensible — *"include a default case in handlers"*). | +| `approveAll` | Drop-in handler that approves everything (test/dev only). | +| `UserInputHandler` (`onUserInputRequest`) | Enables the `ask_user` tool. | +| `ElicitationHandler` (`onElicitationRequest`) | Lets the client present form-based dialogs; flips `session.capabilities.ui.elicitation`. | +| `session.ui` / `SessionUIApi` | UI elicitation surface (full details in readme "UI Elicitation"). | +| `TelemetryConfig` | OpenTelemetry — pass via `new CopilotClient({ telemetry })`. Spans on tool calls, hook invocations, model exchanges; supports trace-context propagation and file export. | +| Error types | Standard `Error` subclasses; readme shows `try/catch` around `session.send`. | + +### 7.3 Canonical 12-line example + +From the readme "Tools" section ([`nodejs/README.md`](https://github.com/github/copilot-sdk/blob/main/nodejs/README.md), verbatim shape): + +```typescript +import { z } from "zod"; +import { CopilotClient, defineTool, approveAll } from "@github/copilot-sdk"; + +const client = new CopilotClient(); // spawns CLI via stdio +const session = await client.createSession({ + model: "gpt-5", + onPermissionRequest: approveAll, // required + tools: [ + defineTool("lookup_issue", { + description: "Fetch issue details from our tracker", + parameters: z.object({ id: z.string() }), + handler: async ({ id }) => fetchIssue(id), // your code + }), + ], +}); +session.on("assistant.message_delta", (e) => process.stdout.write(e.data.delta)); +await session.sendAndWait({ prompt: "Summarise issue ABC-123." }); +await client.stop(); +``` + +### 7.4 Squad's de-facto SDK usage (ground truth) + +Recursive grep of `c:/git/squad/packages/**/*.ts` for `@github/copilot-sdk`: + +| Squad file | What it imports | Why | +|---|---|---| +| [`squad-sdk/src/adapter/client.ts:10`](../squad/packages/squad-sdk/src/adapter/client.ts:10) | `import { CopilotClient } from "@github/copilot-sdk"` | **Only direct value-level SDK import in Squad.** Wraps `CopilotClient` in `SquadClient` for reconnection/OTel. | +| [`squad-sdk/src/adapter/types.ts`](../squad/packages/squad-sdk/src/adapter/types.ts) | (no SDK import) — defines `Squad*` mirror types (`SquadPermissionHandler`, `SquadSessionHooks`, `SquadProviderConfig`, `SquadInfiniteSessionConfig`, …). Comment at line 4: *"All Squad code should import types from this adapter layer, never directly from the Copilot SDK."* | **Insulation layer** against SDK churn. | +| [`squad-sdk/src/tools/index.ts:116`](../squad/packages/squad-sdk/src/tools/index.ts:116) | Re-implements `defineTool` (Squad-flavoured) — **not** a re-export of the SDK's `defineTool`. | Lets Squad register `squad_route`, `squad_decide`, `squad_memory`, `squad_status`, `squad_skill` at the adapter boundary. | +| [`squad-sdk/src/build/bundle.ts:34`](../squad/packages/squad-sdk/src/build/bundle.ts:34) | Lists `@github/copilot-sdk` in `DEFAULT_EXTERNAL` (esbuild externalises it). | Avoids bundling the SDK; ships as runtime peer-style dep. | +| [`squad-cli/src/cli-entry.ts:25–101`](../squad/packages/squad-cli/src/cli-entry.ts:25) | Runtime patcher for the broken `vscode-jsonrpc/node` import in `@github/copilot-sdk@0.1.32`. | Bug-workaround; loads SDK lazily on Node 24+. | +| [`squad-cli/src/cli/commands/doctor.ts:350`](../squad/packages/squad-cli/src/cli/commands/doctor.ts:350) | Health-check that validates the same ESM patch. | Defence in depth. | + +**Squad pin:** `"@github/copilot-sdk": "^0.1.32"` ([`squad-sdk/package.json:235`](../squad/packages/squad-sdk/package.json:235)) — three minor versions behind current `0.3.0`. Squad's adapter layer absorbs the drift via `as Parameters[0]` casts ([`adapter/client.ts:472`](../squad/packages/squad-sdk/src/adapter/client.ts:472)). + +**Surface actually exercised:** `CopilotClient` constructor + `start/stop/forceStop/createSession/resumeSession/listSessions/deleteSession/getLastSessionId/getStatus/getAuthStatus/listModels/ping/on`; `CopilotSession` `send/sendAndWait/abort/getMessages/destroy/on/sessionId`. Squad does **not** use `defineTool`, `approveAll`, `acpServer`, or the file-attachment helpers from the SDK — it re-implements them at the adapter boundary or sidesteps them. (This **corrects the Phase-5a stub** which claimed Squad uses `defineTool`.) + +**Hidden / inferred surface used by Squad:** `client.on(SessionLifecycleEventType, handler)` returning an unsubscribe function (header docs above), session-event dotted naming (`assistant.message_delta`, etc. — mapped in Squad's `EVENT_MAP` at [`adapter/client.ts:48–59`](../squad/packages/squad-sdk/src/adapter/client.ts:48)), `client.stop()` returning `Error[]` (not `void`). + +### 7.5 Embeddability inside a VS Code extension (Path-D signal) + +| Concern | Verdict | Evidence | +|---|---|---| +| Pure-Node API surface (no DOM, no `vscode.*`) | ✅ | SDK has zero `vscode` / `vscode.lm` deps (Q-010 resolution from § 6.2). | +| Node-only runtime deps | 🟡 | Uses `vscode-jsonrpc` (Node IPC), spawns a child process via `CopilotClient.start()` (`useStdio: true` default). Both work in the **VS Code extension host** (which is full Node) but **not** in webviews. | +| Spawns the CLI binary | 🟡 | Default mode is `child_process` over stdio. Bundled CLI (`@github/copilot`) is ~tens of MB; an extension would either pin a peer-install (CLI must be on `PATH`) or ship the CLI inside the VSIX (size + signing concerns). Alternative: `cliUrl` mode connects to a remote CLI server (avoids spawning), per Squad's `useStdio: false` path. | +| Webview compatibility | 🔴 | Cannot run inside the webview process — webviews are sandboxed Chromium with no `child_process` / `fs` / `net` access. SDK calls must live in the extension host and proxy to the webview via `postMessage`. | +| Browser compatibility | 🔴 | Not a browser SDK. | +| Auth | ✅ | Honours `useLoggedInUser` (delegates to CLI's already-authenticated state) or explicit `githubToken`. The extension can defer auth to the user's existing `gh auth login`. | +| Event-loop integration | ✅ | All async, returns Promises; integrates naturally with extension activation. | + +**Verdict — Path D (vault-as-VSIX): 🟡 embeddable with shim.** The SDK *can* run in the VS Code extension host, but a Path-D VSIX must (a) require the user to install `@github/copilot` separately or bundle the CLI, (b) keep all SDK calls in the extension-host process (never the webview), (c) accept process-spawn cost on every session, and (d) re-implement Roo's webview-driven UX as either chat-participant UI or webview ↔ extension-host postMessage bridge. **This nullifies the "trivially embed Squad" hope from Q-010** — Squad is structurally a CLI driver, not an embeddable library, and the SDK inherits that architecture. + +### 7.6 License & versioning policy + +| Dimension | Reading | +|---|---| +| License | MIT — vault-friendly. | +| Stability | **Public preview**, semver `0.x` — *"minor breaking changes may still occur between releases"* (Java release notes mirror this; Node SDK CHANGELOG documents `autoRestart` removal as a recent breaking change). | +| Cadence (rough, since v0.1.0 at end of 2025) | ~54 published versions across ~5 months; observable breaking changes per minor: removed `autoRestart`; new optional params backfilled as optional method params (C#); typed event filtering added (Node #272); new event types added (#868) — broadcast as **forward-compat duties** on the SDK consumer. | +| Compatibility | SDK ↔ CLI compatibility documented at [`docs.github.com — sdk-and-cli-compatibility`](https://docs.github.com/en/copilot/how-tos/copilot-sdk/troubleshooting/sdk-and-cli-compatibility); a given SDK minor pins to a window of CLI versions. Mismatch surfaces as `protocolVersion` errors (Squad checks `client.getStatus().protocolVersion`). | +| Vault risk | 🟡 — depending on the SDK in vault automation means tracking ~monthly minor bumps. Mitigation patterns visible in Squad: (a) wrap SDK types in adapter mirrors, (b) `as Parameters[N]` casts for cross-version configs, (c) runtime ESM patcher for known broken imports, (d) doctor command. | + +--- + +## 8. Roo ↔ Copilot CLI Mapping Table + +### Sources + +- This file §§ 1–6. +- [`10-roo-inventory.md`](10-roo-inventory.md) for Roo-side feature definitions. + +### Findings (2026-04-26) + +| Roo-Code feature | Copilot CLI mechanism | Parity | Notes | +|---|---|---|---| +| Built-in modes (5) | Built-in agents (7: `code-review`, `configure-copilot`, `explore`, `general-purpose`, `research`, `rubber-duck`, `task`) | 🟢 better | More built-ins; `general-purpose` covers `code` mode. | +| `.roomodes` (project) | `.github/agents/*.agent.md` (project) | 🟢 1:1 | Same precedence semantics (project beats user). | +| `~/AppData/.../custom_modes.yaml` (global) | `~/.copilot/agents/*.agent.md` | 🟢 1:1 | Single-file YAML → directory of `.agent.md` files (mechanically convertible). | +| Mode `groups` (read/edit/command/mcp/browser) | `.agent.md` `tools:` array | 🟢 1:1 | Map per § 5.4. | +| Mode `groups[].fileRegex` | None | 🔴 lost | **Same blocker as Chat G-1.** Workaround: prose + `preToolUse` hook on `write`. | +| Mode `allowedMcpServers: [...]` | `.agent.md` `tools: ["server/*"]` + `mcp-servers:` allowlist | 🟢 1:1 | Empty array → omit all. | +| Mode `whenToUse` | None | 🟡 minor | CLI relies on `/agent` picker / `--agent` flag. | +| `roleDefinition` + `customInstructions` | `.agent.md` body | 🟢 1:1 | Concatenate. | +| `~/.roo/rules/` global rules | `~/.copilot/copilot-instructions.md` + `instructions/*.instructions.md` | 🟢 1:1 | Modular `.instructions.md` ≅ Roo's per-file rules. | +| `.roo/rules/` project rules | `.github/copilot-instructions.md` + `.github/instructions/**/*.instructions.md` | 🟢 1:1 | Same cascade. | +| `.roo/rules-/` per-mode rules | None first-class | 🔴 lost | **Same as Chat G-2.** Workaround: inline into agent body. | +| `AGENTS.md` | `AGENTS.md` (read by both CLI and Chat) | 🟢 1:1 | Cross-tool standard. | +| MCP project config (`.roo/mcp.json`) | `.github/mcp.json` (canonical) **or** `.copilot/mcp-config.json` (squad-style) | 🟢 1:1 | Field renames: `mcpServers` ↔ `mcpServers` (same), `disabled` ↔ `enabled`. | +| MCP user config (`mcp_settings.json` in globalStorage) | `~/.copilot/mcp-config.json` | 🟢 1:1 | Symlink target via `COPILOT_HOME`. | +| Per-mode MCP allowlist | `.agent.md` `tools: ["server/*"]` | 🟢 1:1 | | +| Sequential `new_task` orchestrator | `task` tool (parallel-capable; serialise via prose) | 🟡 minor | Same nuance as Chat Q-013. | +| Approval per tool call | Per-tool prompt + `Kind(arg)` allow/deny lists | 🟢 better | Has both interactive and pinnable allowlists. | +| Iteration cap | `--max-autopilot-continues` (autopilot only) | 🟢 better | Roo has none. | +| Webview UI | None — TTY only | 🟡 different | Mode CRUD = edit `.agent.md`; `/agent` picker, `/mcp`, `/skills`, `/instructions` slash commands. | +| Headless / scripting | `-p`, JSONL `--output-format`, exit codes, `--allow-tool` | 🟢 better | Roo has no first-class headless mode. | +| Session resume | `--continue`, `--resume[=name]`, `/rename`, FTS5 search | 🟢 better | Roo persists by VS Code workspace only. | +| Auto-context-management | Auto-compact at ~95% | 🟢 better | Roo has no equivalent. | +| Hooks | 12+ event types, command/HTTP/prompt | 🟢 better | Roo has none. | +| Skills (callable Markdown procedures) | `~/.copilot/skills//SKILL.md` + `.github/skills/` | 🟢 better | Closest Roo analogue: prompt files (planned, not present). | +| BYOK / local model | `COPILOT_PROVIDER_*` env vars (openai / azure / anthropic) | 🟢 better than Chat | **Resolves Q-030 for the CLI path** — Ollama via OpenAI-compat endpoint works. | +| Settings sync | `COPILOT_HOME` symlink + git-tracked `.github/copilot/settings.json` | 🟢 1:1 | Vault-friendly. | +| Org policies | Repo-level `settings.json` (allowlisted keys only) + Enterprise-tier server policies | 🟢 better | Cleaner than Roo. | +| Vault portability (Q-008) | `COPILOT_HOME` env var or `--config-dir` flag | 🟢 resolved | **Resolves Q-008 for the CLI path** — no per-profile-id quirks. | + +**Summary:** **22 of 25 axes are 🟢 (1:1 or better); 2 are 🟡 (minor/nuance); 2 are 🔴 (per-mode `fileRegex`, per-mode rules folder)** — the **same two blockers** as the Chat path. The CLI **adds material wins** in headless scripting, hooks, skills, sessions, and BYOK; it **loses** the webview UI affordances entirely. + +--- + +## 9. MCP Support (Phase 5b-i) + +### Sources + +- [`docs.github.com — add-mcp-servers`](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers). Accessed 2026-04-26. +- [`docs.github.com — cli-command-reference § MCP server configuration`](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#mcp-server-configuration). Accessed 2026-04-26. +- [`docs.github.com — cli-command-reference § Slash commands`](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#slash-commands-in-the-interactive-interface). Accessed 2026-04-26. +- [`docs.github.com — cli-command-reference § Migrating from .vscode/mcp.json`](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#migrating-from-vscodemcpjson). Accessed 2026-04-26. +- [`40-copilot-chat-research.md` § MCP Support (4c)](40-copilot-chat-research.md#mcp-support) — Chat-side schema for the side-by-side. Accessed 2026-04-26. +- [`../squad/.copilot/mcp-config.json`](../../../../squad/.copilot/mcp-config.json) — squad's user-format file used at project scope. + +### Findings (2026-04-26) + +#### 9.1 Canonical config locations & precedence — resolves Q-031 + +The CLI loads MCP servers from **three** layers, namespaced by source: + +| Scope | Path | Schema | Notes | +|---|---|---|---| +| **User** | `~/.copilot/mcp-config.json` (Windows: `%USERPROFILE%\.copilot\mcp-config.json`) | `{ "mcpServers": { … } }` | Created/updated by `/mcp add` and `copilot mcp add`. Follows `COPILOT_HOME`. | +| **Repository** | `.github/mcp.json` | Same `{ "mcpServers": { … } }` | Trust level "Medium — Recommended review" per the CLI command reference. | +| **Workspace** | `.mcp.json` (repo root) | Same | Equal trust to `.github/mcp.json`; convenience for projects that don't use `.github/`. | +| **Per-invocation** | `--additional-mcp-config=JSON\|@file` | Same | Augments user config; *overrides any installed server with the same name*. | + +> "Configure persistent servers in `~/.copilot/mcp-config.json`. Use `--additional-mcp-config` to add servers for a single session." — [cli-command-reference § MCP server configuration](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#mcp-server-configuration) + +**Precedence:** servers are merged across layers; on name collision, **`--additional-mcp-config` > workspace/repo > user**. Built-in servers (`github-mcp-server`, `playwright`, `fetch`, `time`) are highest trust and always available unless disabled with `--disable-builtin-mcps` or `--disable-mcp-server `. + +> ⚠️ **Squad's `.copilot/mcp-config.json` is non-canonical (resolves Q-031).** The CLI's own documentation does **not** list `.copilot/mcp-config.json` at the project root as a discovery location. Squad relies on its launcher implicitly setting `COPILOT_HOME` to the project's `.copilot/` directory, which redirects the **user** layer to that path. Any user who runs bare `copilot` from a squad-shaped project (without the squad launcher) will **not** load that file. **Recommendation for the vault:** prefer the documented `.github/mcp.json` for project-scope MCP and reserve `~/.copilot/mcp-config.json` (via `COPILOT_HOME`) for the vault-symlinked user layer. + +The legacy `.vscode/mcp.json` is **not** read by the CLI; an explicit migration is documented (`jq '{mcpServers: .servers}' .vscode/mcp.json > .mcp.json`) — confirming the schema fork below. + +#### 9.2 Schema vs Copilot Chat's `.vscode/mcp.json` — side-by-side + +| Axis | Copilot CLI (`mcp-config.json` / `.mcp.json` / `.github/mcp.json`) | Copilot Chat (`.vscode/mcp.json`) | +|---|---|---| +| **Top-level key** | `mcpServers` (object map) | `servers` (object map) + optional top-level `inputs` array | +| **Transport names** | `local` / `stdio` (alias), `http`, `sse` | `stdio`, `http`, `sse` (no `local` alias) | +| **Stdio fields** | `command`, `args`, `env`, `cwd`, `tools`, `timeout`, `type` | `command`, `args`, `env`, `envFile`, `sandbox`/`sandboxEnabled` (mac/linux), `type` | +| **HTTP fields** | `type`, `url`, `headers`, `tools`, `oauthClientId`, `oauthPublicClient`, `oidc`, `timeout` | `type`, `url`, `headers` | +| **Per-server tool filter** | `tools: ["*"]` / `["tool_a","tool_b"]` (required field) | No equivalent in `mcp.json`; tool filtering is via `.agent.md` `tools:` only | +| **Secret substitution** | `${VAR}`, `$VAR`, `${VAR:-default}` from **process env** (no Credential-Manager prompt) | `${input:id}` resolved from top-level `inputs:` array → first-run prompt → **Windows Credential Manager** | +| **CLI-only fields** | `tools`, `timeout`, `oidc`, `oauthClientId`, `oauthPublicClient`, `filterMapping` | n/a | +| **VS-Code-only fields** | n/a | `inputs`, `envFile`, `sandbox*`, top-level `gallery`/`dev` UX hints | +| **Disable mechanism** | `/mcp disable ` (per-session); `--disable-mcp-server` (per-invocation); deletion via `/mcp delete` | UI toggle in the Chat MCP picker; per-server `disabled: true` | + +> "If your project uses `.vscode/mcp.json` (VS Code's MCP configuration format), migrate to `.mcp.json` for GitHub Copilot CLI. The migration remaps the `servers` key to `mcpServers`." — [cli-command-reference](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#migrating-from-vscodemcpjson) + +#### 9.3 Auth & secrets on Windows — resolves Q-033 + +The CLI's secret model is **process-env substitution only**. Per the field reference: `env … Supports $VAR, ${VAR}, and ${VAR:-default} expansion.` There is **no** equivalent of Chat's `${input:…}` first-run prompt, and the OS keychain is **only** used for the user's GitHub auth token, **not** for MCP-server secrets. + +**Recommended Windows pattern for the vault:** + +```powershell +# Persist a secret in user-scope env (survives reboots; visible to all GUI apps). +[Environment]::SetEnvironmentVariable("TRELLO_API_KEY", "tk_…", "User") +[Environment]::SetEnvironmentVariable("TRELLO_TOKEN", "ATTAxxx", "User") +# Then any mcp-config.json with "env": { "TRELLO_API_KEY": "${TRELLO_API_KEY}" } resolves transparently. +``` + +For projects that prefer file-based secrets, wrap `copilot` in a launcher that loads `.copilot/.env` (gitignored) and exports each `KEY=VAL` to the child process before exec — this is exactly the pattern squad's launcher uses. Windows Credential Manager is **not** the default path on the CLI side (vs Chat); using it requires a wrapper script that calls `[Microsoft.Win32.Credentials]` to read the entry and re-exports the value as an env var before invoking `copilot`. + +> ⚠️ **No shared secret-handling story across Chat and CLI (Q-033 confirmed).** A given MCP server requires *two* configs — `${input:KEY}` for `.vscode/mcp.json` and `${KEY}` (or hardcoded) for `mcp-config.json`. Vault playbook (Phase 8) must pick one canonical source of truth and generate the other. + +#### 9.4 Per-agent MCP filtering + +Filtering is performed at **two** layers and the CLI's behaviour matches Chat exactly for the agent layer: + +1. **`.agent.md` frontmatter `tools:`** — array of bare tool names, `/` pairs, or `/*` wildcards. This is the same syntax documented for VS Code (Q-002 resolved earlier). Default is `["*"]` (all tools). +2. **`.agent.md` frontmatter `mcp-servers:`** — an object that **inlines** an additional MCP-config map scoped to that agent only (uses the same `mcpServers` schema). This is a CLI extension over Chat's `.agent.md` schema — Chat agents reference servers but cannot define new ones inline. + +Combined with Roo's empty-array semantic (Q-009 resolved), the vault's per-mode `allowedMcpServers: ["github"]` translates 1:1 to `tools: ["github-mcp-server/*"]` plus the same in `mcp-servers:` if the project wants the server scoped to that agent only. + +#### 9.5 `/mcp` REPL slash commands + +Per [cli-command-reference § Slash commands](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#slash-commands-in-the-interactive-interface): + +> `/mcp [show|add|edit|delete|disable|enable|auth|reload] [SERVER-NAME]` — Manage the MCP server configuration. + +| Slash | Effect | +|---|---| +| `/mcp show` | List all configured servers and their connection status (a known UX gap: no inline disable button — see [`copilot-cli#2956`](https://github.com/github/copilot-cli/issues/2956)). | +| `/mcp show ` | Detailed status + tool inventory for one server. | +| `/mcp add` | Interactive form (Tab-navigated) for name/type/command/url/env/headers/tools. Hot-reloads — no restart. | +| `/mcp edit ` | Edit an existing server. | +| `/mcp delete ` | Remove a server from the user config. | +| `/mcp disable ` | Keep config; skip server for the rest of the session. | +| `/mcp enable ` | Re-enable a previously disabled server. | +| `/mcp auth ` | Trigger fresh OAuth flow for a remote server in `needs-auth` state (browser-based). | +| `/mcp reload` | Re-read configs from disk (pick up changes made outside the REPL). | + +There is also a non-interactive twin: `copilot mcp [list|get|add|remove]` runs the same operations from the parent shell without entering a session ([CLI command reference § `copilot mcp`](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#copilot-mcp-subcommand)). + +--- + +## 10. Hooks (Phase 5b-i — headline section) + +### Sources + +- [`docs.github.com — use-hooks (CLI how-to)`](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-hooks). Accessed 2026-04-26. +- [`docs.github.com — Hooks configuration (reference)`](https://docs.github.com/en/copilot/reference/hooks-configuration). Accessed 2026-04-26. +- [`docs.github.com — Use hooks with Copilot CLI (tutorial)`](https://docs.github.com/en/copilot/tutorials/copilot-cli-hooks). Accessed 2026-04-26 — **primary source for the PowerShell example** in § 10.4. +- [`docs.github.com — cli-command-reference § Hooks reference`](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#hooks-reference). Accessed 2026-04-26. +- [`docs.github.com — cli-command-reference § Configuration file settings`](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#configuration-file-settings) — `disableAllHooks` semantics. +- [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) — preToolUse not enforced in subagents (active bug; affects verdict). +- [`copilot-cli#2540`](https://github.com/github/copilot-cli/issues/2540) — plugin-defined preToolUse hooks don't fire (active bug). +- [`copilot-cli#2893`](https://github.com/github/copilot-cli/issues/2893) — preToolUse silently bypassed under parallel tool calls (timeout race; active bug). +- [`copilot-cli#2013`](https://github.com/github/copilot-cli/issues/2013) — `hookSpecificOutput.updatedInput` ignored (CLI does not honour the VS Code-style `modifiedArgs` even though docs list it). + +### Findings (2026-04-26) + +#### 10.1 Storage paths & precedence + +Hooks live in **three** layers; all matching layers' hooks **execute in series, repository hooks after user hooks** (per the repo-settings `hooks` merge rule "Concatenated — repository hooks run after user hooks"). + +| Scope | Path(s) | Format | +|---|---|---| +| **User** | `~/.copilot/config.json` (`hooks` key inline) **and/or** any `~/.copilot/hooks/*.json` file ⚠️ uncertain — Q-036 | JSON object, version 1 | +| **Repository** | `.github/hooks/*.json` (one or more files; *.json filename is free-form) | JSON object, version 1 | +| **Repository, alternate** | `.github/copilot/settings.json` `hooks` key (committed; allowlisted) | Inline object | + +> "Hook configuration files are loaded automatically from `.github/hooks/*.json` in your repository." — [cli-command-reference § Hooks reference](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#hooks-reference) + +Discovery follows `COPILOT_HOME`, so a vault-redirected `~/.copilot/` works the same way. + +#### 10.2 Hook events — full enumeration (13 events × ≥2 payload shapes) + +The CLI's hook event registry, grouped by category. Two payload shapes are emitted depending on whether the event is configured under its **camelCase** name (native) or its **PascalCase** alias (VS Code Copilot extension compatible — fields shift to snake_case and gain `hook_event_name`). + +**Session lifecycle:** + +| Event (camelCase / PascalCase) | Trigger | Key fields | Output processed | +|---|---|---|---| +| `sessionStart` / `SessionStart` | New session begins or one is resumed (`source: "new" \| "resume" \| "startup"`) | `sessionId`, `timestamp`, `cwd`, `source`, `initialPrompt` | No (output ignored) | +| `sessionEnd` / `SessionEnd` | Session terminates | `sessionId`, `timestamp`, `cwd`, `reason: "complete" \| "error" \| "abort" \| "timeout" \| "user_exit"` | No | +| `userPromptSubmitted` / `UserPromptSubmit` | Each user prompt is submitted | `sessionId`, `timestamp`, `cwd`, `prompt` | No (cannot mutate the prompt — confirmed in [hooks-configuration § userPromptSubmitted](https://docs.github.com/en/copilot/reference/hooks-configuration#user-prompt-submitted-hook): *"prompt modification not currently supported in customer hooks"*) | +| `agentStop` / `Stop` | Main agent finishes a turn | `sessionId`, `cwd`, `transcriptPath`, `stopReason: "end_turn"` | Yes — `{decision:"block", reason}` forces another turn | + +**Tool lifecycle:** + +| Event | Trigger | Key fields | Output processed | +|---|---|---|---| +| `preToolUse` / `PreToolUse` | Before each tool runs | `toolName`, `toolArgs` (JSON string of tool args; `tool_input` parsed in PascalCase mode) | **Yes — allow / deny / (claimed) modifiedArgs** | +| `postToolUse` / `PostToolUse` | After successful tool completion | `toolName`, `toolArgs`, `toolResult: { resultType:"success", textResultForLlm }` | Yes (SDK only — command hooks ignored) | +| `postToolUseFailure` / `PostToolUseFailure` | After tool fails | `toolName`, `toolArgs`, `error` | Yes — exit code `2` causes stderr to be returned as recovery guidance for the LLM | + +**Sub-agent lifecycle:** + +| Event | Trigger | Key fields | Output processed | +|---|---|---|---| +| `subagentStart` | Just before a sub-agent runs | `agentName`, `agentDisplayName`, `agentDescription`, `transcriptPath` | Returns `additionalContext` prepended to the sub-agent's prompt | +| `subagentStop` / `SubagentStop` | Sub-agent completes | `agentName`, `transcriptPath`, `stopReason` | Same `{decision:"block", reason}` semantics as `agentStop` | + +**Other:** + +| Event | Trigger | Key fields | Output processed | +|---|---|---|---| +| `preCompact` / `PreCompact` | Before manual or auto context compaction | `transcriptPath`, `trigger:"manual"\|"auto"`, `customInstructions` | No (notification only) | +| `permissionRequest` | About to show user a permission dialog (after rule-based checks miss) | regex `matcher` on `toolName` | Yes — `{behavior:"allow"\|"deny", message, interrupt?}`; exit code `2` ≡ deny | +| `errorOccurred` / `ErrorOccurred` | Any execution error | `error{message,name,stack}`, `errorContext`, `recoverable` | No | +| `notification` | Async system notification (shell completed, agent idle, permission prompt, elicitation) | `notification_type`, `message`, `title` | Optional `additionalContext` injection | + +**Exit-code conventions (command hooks):** the documented contract from the references is sparse but consistent: + +- **`preToolUse`**: emit JSON to stdout (`{permissionDecision:"deny", permissionDecisionReason:"…"}`) to block; emit empty/`{}` or `{permissionDecision:"allow"}` to allow. Exit code itself is *not* the primary deny signal; the JSON payload is. Non-zero exit + no JSON ≡ allow with the failure logged ("Hook failures (non-zero exit codes or timeouts) are logged and skipped — they never block agent execution" — [cli-command-reference § Hooks reference](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#hooks-reference)). +- **`permissionRequest`**: exit code `2` ≡ deny; JSON output also accepted. +- **`postToolUseFailure`**: exit code `2` triggers `stderr → additionalContext` for recovery. +- **All others**: exit code is informational; failures are logged and never block. + +Default per-hook timeout is **30 seconds** (`timeoutSec` overrides; max not documented — `⚠️ uncertain — Q-036`). + +#### 10.3 Hook formats: command vs prompt (no separate "JSON config-pointing-to-command" type) + +The reference documents **two** hook types — not three: + +1. **`command`** (all events): runs a shell script with both Bash and PowerShell commands declared on the same hook entry (the CLI picks the right one for the host OS): + ```json + { "type": "command", + "bash": "./scripts/policy.sh", + "powershell": "./scripts/policy.ps1", + "cwd": ".github/hooks", + "env": { "MY_VAR": "value" }, + "timeoutSec": 30 } + ``` + The **JSON config file *is* the script-pointer**: the schema does not separate "config" from "script" — every hook entry is a JSON object that points at a command. Inline scripts are not supported; the command must reference an executable on disk or a one-liner like `pwsh -NoProfile -Command "…"`. + +2. **`prompt`** (`sessionStart` only): auto-submits text as if the user typed it (natural language or `/slash-command`), running before any `--prompt`-passed initial prompt. Useful for "always start in plan mode" or "always run /init" defaults. + ```json + { "type": "prompt", "prompt": "/plan Always begin by reading AGENTS.md." } + ``` + +> ⚠️ **No `http` hook type on the CLI side (correction to the Phase-5a stub).** The Phase-5a placeholder claimed three hook types (`command`, `http`, `prompt`) and an HTTPS-required model for `preToolUse`/`permissionRequest`. The reference documents **only** `command` and `prompt`. The earlier note conflated the **Cloud-agent** hook surface (which does support HTTPS endpoints and an SSRF allowlist) with the **CLI** hook surface (local commands only). Filed as **Q-038** for confirmation against the SDK's `Hook` interface. + +#### 10.4 `preToolUse` deep-dive — the `fileRegex` substitute + +This hook is the **headline finding** because it is the only first-class CLI mechanism that can replace Roo's per-mode `fileRegex` edit restriction. Payload (camelCase form): + +```text +sessionId : string +timestamp : number # Unix ms +cwd : string # absolute working dir +toolName : string # "edit" | "create" | "apply_patch" | "bash" | "powershell" | "view" | "web_fetch" | "task" | +toolArgs : string # JSON-stringified tool arguments — must be parsed +``` + +Key facts that determine whether `preToolUse` substitutes for `fileRegex`: + +- For **`edit`** / **`create`** / **`apply_patch`**, `toolArgs` (after parse) contains a `path` field (relative or absolute). This is the field a `fileRegex` policy must match against. +- The active **agent name is not in the payload**. Agent identity must be threaded in via an env var that the CLI sets when launching the hook, or via a wrapper that records the active agent in a sidecar file. ⚠️ **uncertain — Q-037: which env vars (if any) does the CLI export to spawned hook processes that identify the active `--agent` and current sub-agent depth?** The squad-style approach is to write the agent name to `~/.copilot/state/active-agent.txt` from a `subagentStart` hook and have `preToolUse` read it back. +- The hook's working directory is whatever the CLI was launched from unless `cwd` overrides it (relative paths resolve from there). + +**Concrete Windows PowerShell example** — mimics Roo's `fileRegex: "\\.md$"` for the `edit` tool, restricted to a `docs-writer` agent. Cited primary source for the deny-output JSON shape and the `[Console]::In.ReadToEnd() | ConvertFrom-Json` reading pattern: [tutorial step 5](https://docs.github.com/en/copilot/tutorials/copilot-cli-hooks#5-enforce-policies-with-pretooluse) and [hooks-configuration § Pre-tool use hook](https://docs.github.com/en/copilot/reference/hooks-configuration#pre-tool-use-hook). + +`.github/hooks/file-regex.policy.json`: + +```json +{ + "version": 1, + "hooks": { + "preToolUse": [ + { + "type": "command", + "powershell": "pwsh -NoProfile -ExecutionPolicy Bypass -File ./.github/hooks/scripts/enforce-file-regex.ps1", + "bash": "./.github/hooks/scripts/enforce-file-regex.sh", + "timeoutSec": 5 + } + ] + } +} +``` + +`.github/hooks/scripts/enforce-file-regex.ps1`: + +```powershell +$ErrorActionPreference = 'Stop' + +# 1. Read the JSON payload from stdin (CLI feeds it here per hooks-configuration ref). +$inputObj = [Console]::In.ReadToEnd() | ConvertFrom-Json + +$toolName = $inputObj.toolName +# Only restrict file-mutation tools. +if ($toolName -notin @('edit', 'create', 'apply_patch')) { exit 0 } + +# 2. toolArgs is a JSON STRING — must be parsed again. +$toolArgs = $null +try { $toolArgs = $inputObj.toolArgs | ConvertFrom-Json } catch { exit 0 } +$path = $toolArgs.path +if (-not $path) { exit 0 } + +# 3. Determine active agent. The CLI does not yet expose this in payload (Q-037), +# so the convention is: subagentStart writes the name into this state file. +$activeAgent = '' +$stateFile = Join-Path $env:USERPROFILE '.copilot\state\active-agent.txt' +if (Test-Path $stateFile) { $activeAgent = (Get-Content $stateFile -Raw).Trim() } + +# 4. Per-agent fileRegex policy table (mirror of .roomodes "groups[].fileRegex"). +$policy = @{ + 'docs-writer' = '\.md$' + 'translate' = '(locales|i18n)[\\/].*\.(json|md)$' + 'devops' = '\.(ya?ml|tf|hcl|dockerfile|ps1|sh)$' +} + +if ($policy.ContainsKey($activeAgent)) { + $regex = $policy[$activeAgent] + if ($path -notmatch $regex) { + # 5. Emit deny verdict per hooks-configuration § Pre-tool use hook. + @{ + permissionDecision = 'deny' + permissionDecisionReason = "Agent '$activeAgent' may only edit files matching /$regex/. Refusing to modify '$path'." + } | ConvertTo-Json -Compress + exit 0 + } +} + +exit 0 # allow by default +``` + +**Verified payload-shape claims** against the primary doc: + +> "**Input JSON:** `{ "timestamp": …, "cwd": …, "toolName": "bash", "toolArgs": "{\"command\":\"rm -rf dist\",…}" }` … **Fields:** `toolArgs`: JSON string containing the tool's arguments." — [hooks-configuration § Pre-tool use hook](https://docs.github.com/en/copilot/reference/hooks-configuration#pre-tool-use-hook) + +> "**Output fields:** `permissionDecision`: Either `"allow"`, `"deny"`, or `"ask"` (only `"deny"` is currently processed). `permissionDecisionReason`: Human-readable explanation for the decision." — *ibid.* + +The tutorial's enforce-file-permissions example ([same page](https://docs.github.com/en/copilot/tutorials/copilot-cli-hooks#5-enforce-policies-with-pretooluse)) confirms the parse-and-match-on-`path` pattern verbatim: +> *"if [ "$TOOL_NAME" = "edit" ]; then PATH_ARG=$(echo "$INPUT" | jq -r '.toolArgs' | jq -r '.path'); if [[ ! "$PATH_ARG" =~ ^(src/|test/) ]]; then echo '{"permissionDecision":"deny", …}'."* + +**Known unknowns the example carries (tracked as Q-035 follow-ups):** + +- **Latency:** `pwsh -NoProfile -Command …` cold-start on Windows is ~150–400 ms per invocation; uncached PowerShell module loads can push that to >1 s. With a 30 s hook timeout this is comfortably safe per call but adds visible lag on tool-heavy turns. Filed as **Q-039** for empirical measurement on the user's box. +- **Env-var inheritance:** the CLI's hook process inherits the user-shell environment by default; setting `env: { … }` in the hook entry adds/overrides. Whether `${env:VAR}` expansion works inside the entry's `env` map (it works in MCP `env`) is `⚠️ uncertain — Q-040`. +- **Sub-agent enforcement gap (CRITICAL — affects verdict):** [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) — *"`preToolUse` hooks configured in config.json are correctly enforced on the main agent, but are not enforced on subagents spawned via the `task` tool."* As of the issue's last update this is **unresolved**. A `task`-dispatched sub-agent invoking `edit("README.md")` will bypass the policy. The vault's orchestrator pattern dispatches frequently; this materially weakens the workaround. +- **Parallel-call race (CRITICAL):** [`copilot-cli#2893`](https://github.com/github/copilot-cli/issues/2893) — *"`preToolUse` hooks are silently bypassed under parallel tool calls because `timeoutSec` does not terminate the hook process — when a hook takes [longer], the tool call proceeds anyway."* Multi-tool turns can leak past the policy. +- **Plugin hooks broken:** [`copilot-cli#2540`](https://github.com/github/copilot-cli/issues/2540) — `preToolUse` hooks defined in a *plugin's* `hooks.json` do not fire at all; only repo + user hooks are reliable today. +- **`modifiedArgs` not honoured:** [`copilot-cli#2013`](https://github.com/github/copilot-cli/issues/2013) — the docs list a `modifiedArgs` output field for `preToolUse`, but the CLI ignores it. Mutating the proposed write path (e.g., re-routing edits to a quarantine dir) is **not** an option today. + +#### 10.5 `disableAllHooks` kill-switch — resolves Q-032 + +`disableAllHooks: true` is one of only six keys honoured at the **repository** layer (`.github/copilot/settings.json`); it disables every user, repo, and plugin hook for sessions started in that repo (per [cli-command-reference § Repository settings](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#repository-settings-githubcopilotsettingsjson)). It is also honoured at the user layer. + +> ⚠️ **Safety note.** Because the kill-switch lives in a *committed* repository file, anyone with write access to a project can disable that project's enforcement by adding one boolean to `.github/copilot/settings.json`. For policy-critical environments, gate the file behind branch protection / required code review, or pin the policy at the **user** layer (which the repo can't override) and accept the loss of per-repo opt-out. + +This **partially resolves Q-032** (repo settings allowlist scope): per-project `allowedTools` / `deniedTools` / `systemPrompt` are still ignored at the repo layer (Q-032 stands), but `disableAllHooks` and `hooks` themselves *are* committed-honour-able — which is exactly what the vault needs to ship per-project enforcement. + +#### 10.6 Verdict — does `preToolUse` realistically replace Roo's `fileRegex`? + +**Yes-with-caveats.** For the **main agent** on serial tool calls, `preToolUse` mechanically substitutes for `fileRegex`: the payload exposes `toolName` + parsed `toolArgs.path`, and the `{permissionDecision:"deny", permissionDecisionReason}` JSON output blocks the call exactly the way Roo's pre-edit check does. The PowerShell example above is a working drop-in for Roo's `fileRegex: "\\.md$"`. + +**The caveats are non-trivial and must be accepted explicitly:** + +1. **Sub-agent bypass ([#2392](https://github.com/github/copilot-cli/issues/2392)) is the binding constraint.** The vault's orchestrator delegates to specialists via `task(agent="…")`; if those sub-agents bypass `preToolUse`, the per-agent file restriction is **not enforced** on the most common path. Mitigation: until the bug is fixed, restrict orchestrator-style work to `--agent ` boot mode rather than `task`-dispatched sub-agents, or explicitly forbid sub-agent dispatch in agent bodies that need file-regex enforcement. +2. **Parallel-call race ([#2893](https://github.com/github/copilot-cli/issues/2893)) leaks under load.** Mitigation: keep hook scripts under ~50 ms of work and pre-compile (avoid module imports inside the hot path). +3. **Active-agent identity not in the payload (Q-037).** Requires a sidecar file written from `subagentStart` to thread agent name through. Workable but adds moving parts. +4. **Plugin-hook bug ([#2540](https://github.com/github/copilot-cli/issues/2540)).** Don't ship the policy as a plugin; ship it as a repo or user hook. + +**Bottom line for Path-B (CLI-first):** `preToolUse` **does close the G-1 blocker for serial main-agent flows** (which is most of Roo's actual `fileRegex` usage in the vault — the per-mode "docs-writer can only edit `.md`" pattern), but it **does not close it for orchestrator/sub-agent flows** until #2392 ships. That makes G-1 a 🟠 *major* on the CLI path rather than a 🔴 *blocker* — a meaningful improvement over the Chat path (which has no hook surface at all and stays 🔴), but not a clean parity win. Phase 6 should record G-1 as **🟠 major (CLI)** and **🔴 blocker (Chat)** when the Gap Catalog is unified. + +--- + +## 11. Skills (Phase 5b-ii-A) + +### Sources + +- [`docs.github.com — Adding agent skills for GitHub Copilot CLI`](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills) — canonical CLI how-to (path was renamed from `/use-skills` to `/add-skills`). Accessed 2026-04-26. +- [`docs.github.com — About agent skills`](https://docs.github.com/en/copilot/concepts/agents/about-agent-skills) — concepts page. Accessed 2026-04-26. +- [`docs.github.com — Custom skills (SDK)`](https://docs.github.com/en/copilot/how-tos/copilot-sdk/use-copilot-sdk/custom-skills) — SDK-side counterpart. Accessed 2026-04-26. +- [`agentskills.io`](https://agentskills.io/) — open Agent Skills standard the format implements (cross-tool with Claude Code, Cursor, Gemini CLI, Codex CLI). Accessed 2026-04-26. +- [`microsoft/vscode-copilot-release#14131`](https://github.com/microsoft/vscode-copilot-release/issues/14131) — VS Code SKILL.md frontmatter validator does not recognise `allowed-tools` (active bug). Accessed 2026-04-26. +- [`copilot-cli#978`](https://github.com/github/copilot-cli/issues/978) — Skills not auto-triggered unless explicitly named in prompt (reported regression). Accessed 2026-04-26. +- [`anthropics/claude-code#18737`](https://github.com/anthropics/claude-code/issues/18737) — `allowed-tools` only honoured by the Claude CLI, not by Skills running under Claude on the API/Plugins surface (cross-tool portability caveat). Accessed 2026-04-26. +- [`../squad/.copilot/skills/`](../../../../squad/.copilot/skills) — Squad's actual project-skills directory (23 `SKILL.md` files at investigation time). Accessed 2026-04-26. + +### Findings (2026-04-26) + +#### 11.1 What a skill is + +> "Agent skills are folders of instructions, scripts, and resources that Copilot can load when relevant to improve its performance in specialized tasks." — [add-skills](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills) + +A skill is a **directory** (not a single file) containing one mandatory `SKILL.md` plus optional sibling resources (helper Markdown files, shell/PowerShell scripts, JSON examples, …). When the agent invokes the skill, the **entire directory contents are made available alongside the `SKILL.md` instructions** — so a skill can ship its own enforcement script, sample data, or templates and reference them by relative path from the `SKILL.md` body. This is the load-bearing mechanism that turns a skill into an *executable* Markdown procedure rather than just additional prose. + +Skills implement the open [Agent Skills standard](https://agentskills.io/), which means a directory written for Copilot CLI is also discovered (with caveats — see § 11.5) by Claude Code, Cursor, Gemini CLI, and Codex CLI. This is one of the few customization surfaces in Copilot that is genuinely cross-tool by design. + +#### 11.2 File format & frontmatter + +`SKILL.md` is YAML-frontmatter Markdown. Filename is **literal** — `SKILL.md` only; `skill.md`/`Skill.md` will be ignored. + +```markdown +--- +name: github-actions-failure-debugging +description: Guide for debugging failing GitHub Actions workflows. Use this when asked to debug failing GitHub Actions workflows. +license: MIT +allowed-tools: shell +--- + +When asked to debug a failing GitHub Actions run: + +1. Use `list_workflow_runs` (GitHub MCP) to find recent runs. +2. Use `summarize_job_log_failures` to AI-summarise failed jobs. +3. If still ambiguous, fall through to `get_job_logs` for the raw logs. +4. Reproduce locally; commit the fix. +``` + +Frontmatter fields documented for the **Copilot CLI flavour**: + +| Field | Required | Purpose | +|---|---|---| +| `name` | ✅ | Lowercase, hyphen-separated, ≤ 64 chars; typically matches the directory name. Acts as the slash-command name (`/`). | +| `description` | ✅ | The autonomous-trigger string. Copilot loads the skill into context when a user prompt aligns with this description — write it like a search-engine snippet (verbs + concrete trigger phrases + technologies). Vague descriptions silently fail to trigger ([copilot-cli#978](https://github.com/github/copilot-cli/issues/978)). | +| `license` | ⬜ | Free-text license note (e.g., `MIT`). Informational only. | +| `allowed-tools` | ⬜ | Pre-approval list to skip per-call confirmation prompts. The official guidance is explicit: ⚠️ *"Only pre-approve the `shell` or `bash` tools if you have reviewed this skill and any referenced scripts, and you fully trust their source."* Note: the VS Code Copilot extension's frontmatter validator currently warns on `allowed-tools` even though the CLI accepts it ([vscode-copilot-release#14131](https://github.com/microsoft/vscode-copilot-release/issues/14131)). | + +> ⚠️ **Cross-tool fields not in the CLI flavour.** The Anthropic / Claude Code skill spec also defines `user-invocable` and `disable-model-invocation` to control slash-menu visibility and to prevent autonomous use respectively. These fields are **not documented for the Copilot CLI** and are silently ignored when present (filed as **Q-041**). Authors targeting both runtimes must accept that the model-invocation policy is essentially "always autonomous-eligible" on Copilot. + +#### 11.3 Storage paths & precedence + +Per the canonical doc, the CLI scans two scope tiers, each with three brand-equivalent aliases (so existing Claude / Anthropic skill libraries drop in without renames): + +| Scope | Default path(s) | Notes | +|---|---|---| +| **User** (cross-project) | `~/.copilot/skills//SKILL.md`, `~/.claude/skills//SKILL.md`, `~/.agents/skills//SKILL.md` | Follows `COPILOT_HOME` for the `.copilot/` variant; the `.claude/` and `.agents/` variants are scanned at the literal home path. Vault recommendation: redirect `~/.copilot/skills/` via `COPILOT_HOME` and skip the other two for clarity. | +| **Project** (per-repo) | `.github/skills//SKILL.md`, `.claude/skills//SKILL.md`, `.agents/skills//SKILL.md` | Repo-relative. The canonical Copilot location is `.github/skills/`. | + +Precedence: project beats user when names collide (same as agents and instructions). Plugins can also bundle skills, which appear at lowest priority and can be overridden by either tier. + +#### 11.4 Invocation model — autonomous + explicit slash + REPL management + +Copilot loads a skill in **three** distinct ways: + +1. **Autonomous (description-driven).** Copilot indexes every discovered skill's `name` + `description` at session start; when a user prompt's intent aligns with the description, Copilot loads `SKILL.md` plus the directory contents into the agent's context for that turn. This is the path the docs lead with and is the reason the description must be specific. (Active complaint that this is unreliable in practice: [copilot-cli#978](https://github.com/github/copilot-cli/issues/978).) +2. **Explicit slash invocation in a prompt.** Reference the skill by name with a leading slash anywhere in the prompt: `Use the /frontend-design skill to create a responsive navigation bar in React.` This bypasses the description-matching heuristic and forces the load. +3. **Interactive REPL management** via the `/skills` slash family: + - `/skills list` (or the natural-language *"What skills do you have?"*) — enumerate. + - `/skills info [SKILL-NAME]` — show description, location, and which plugin (if any) shipped it. + - `/skills` (no arg) — interactive enable/disable picker (arrow keys + space). + - `/skills reload` — re-scan disk after adding a new skill mid-session. + - `/skills add ` — register an additional skills root. + - `/skills remove ` — delete a user-installed skill (plugin-shipped skills must be removed via the plugin). + +#### 11.5 Squad ground-truth (project-scope, 23 SKILL.md files) + +Squad ships project-scope skills under [`../squad/.copilot/skills/`](../../../../squad/.copilot/skills) — note the **non-canonical location** (`.copilot/skills/`, not `.github/skills/`); these are loaded only because squad's launcher implicitly redirects `COPILOT_HOME` to the project's `.copilot/` directory (same convention pattern documented as Q-031 for MCP). At investigation time there are **23 SKILL.md files** (the original brief estimated 24; the directory was re-scanned and 23 is the true count). + +Representative skills (sample — not exhaustive) drawn from the directory listing only, one-line purposes inferred from the directory names per the task brief's no-deep-read instruction: + +| Skill | Inferred purpose | +|---|---| +| `agent-collaboration/` | How agents hand off work to each other within a squad. | +| `agent-conduct/` | Behavioural norms for agent output (tone, refusals, escalation). | +| `architectural-proposals/` | Procedure for drafting and circulating architecture proposals. | +| `cli-wiring/` | How squad agents invoke the Copilot CLI (`-p`, `--agent-cmd`, model selection). | +| `git-workflow/` | Branching, commit-message, and PR conventions. | +| `init-mode/` | First-run scaffolding for a new squad-enabled repo. | +| `pr-lifecycle/` | Open → review → merge → close pull-request playbook. | +| `protected-files/` | Guard rails preventing edits to sensitive paths (analogue to Roo's `fileRegex`). | +| `secret-handling/` | Never-log / env-var-only patterns for credentials. | +| `windows-compatibility/` | PowerShell-equivalent commands for skills authored Bash-first. | +| `distributed-mesh/` | (ships extra resources: `mesh.json.example`, `sync-mesh.ps1`, `sync-mesh.sh`) Multi-machine squad coordination. | + +Other skills present (names only): `architectural-review`, `ci-validation-gates`, `client-compatibility`, `github-multi-account`, `history-hygiene`, `model-selection`, `release-process`, `reskill`, `reviewer-protocol`, `security-review`, `squad-conventions`. The `distributed-mesh/` directory is the clearest example of the *"skill = directory of resources"* model — its `SKILL.md` references both a Bash and a PowerShell sync script, the cross-platform pattern Squad apparently adopts everywhere it ships scripts. + +The practical takeaway for the vault: **skills are the natural home for Roo's per-mode "way of working" prose** that today lives in `roleDefinition` / `customInstructions` / `.roo/rules-/`. A skill bundle (`SKILL.md` + helper script) maps cleanly onto the *"only edit `.md` files"* + *"format with prettier afterwards"* + *"emit a Conventional-Commits message"* triplet that a vault docs-writer mode wants. + +#### 11.6 Roo comparison — additive over Roo + +Roo has **no first-class skills concept**. The closest analogues each cover only part of what a skill does: + +| Roo construct | What it provides | What skills add over it | +|---|---|---| +| `.roo/rules-/*.md` | Per-mode declarative instruction files (always-on while that mode is active). | Skills are **executable** (can include shell scripts the agent runs), and they are **dynamically loaded on-demand** by description-matching, not always-on — which keeps the system prompt small. | +| Orchestrator's `new_task(mode, prompt)` boomerang | Model-driven dispatch of a sub-agent that runs and returns. | Skills compose *without* spawning a new agent; the same agent picks the skill up mid-turn. Skills are also reusable across modes/agents, whereas a `new_task` payload is per-invocation. | +| Mode `customInstructions` | Per-mode prose appended to the system prompt. | Same scope (per-task instructions) but skills can also bundle **resources** (sample files, scripts) and are loaded *only* when relevant — `customInstructions` are paid for on every turn in that mode. | + +**Net assessment: skills are a strict additive capability over Roo, particularly relevant for Path-B (CLI-first) playbook design.** They give the vault a place to encode the procedural memory ("when about to publish a release, run `release-checks.ps1` and …") that today lives scattered across rule files, custom instructions, and tribal knowledge. They are also **the most natural CLI counterpart to VS Code Copilot Chat's `*.prompt.md` files** — both are reusable Markdown procedures with frontmatter, the difference being that prompts are user-invoked (`/promptname`) whereas skills are model-invoked-by-description (`/skillname` is the override path, not the primary one). + +#### 11.7 Cross-platform note (Windows-first vault concern) + +The official skill examples ship Bash-first scripts (`./convert-svg-to-png.sh`, `./scripts/policy.sh`); the doc's tutorial uses `if [ "$TOOL_NAME" = "edit" ]; then …` Bash syntax verbatim. **A skill that calls a `.sh` script will fail silently on Windows when `pwsh`/`bash` is not on PATH** unless the skill ships a parallel `.ps1` and the `SKILL.md` body branches on platform. Squad's `distributed-mesh/` skill is the working pattern: it ships both `sync-mesh.sh` and `sync-mesh.ps1` and presumably tells the agent in the `SKILL.md` body to choose by `$IsWindows` / `uname`. The vault's Phase-8 playbook should adopt this dual-shipping pattern as a hard rule for any skill that exposes a script — and any skill that pre-approves `bash` via `allowed-tools` should also pre-approve `shell` (the PowerShell tool family on Windows) or it will prompt-storm the user on every Windows invocation. + +--- + +## 12. Scripting / automation (Phase 5b-ii-A) + +### Sources + +- [`docs.github.com — Quickstart for automating with GitHub Copilot CLI`](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/quickstart). Accessed 2026-04-26. +- [`docs.github.com — Running GitHub Copilot CLI programmatically`](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically). Accessed 2026-04-26. +- [`docs.github.com — CLI command reference § Command-line options`](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#command-line-options). Accessed 2026-04-26. +- [`docs.github.com — CLI programmatic reference`](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-programmatic-reference). Accessed 2026-04-26. +- [`docs.github.com — Automating tasks with Copilot CLI and GitHub Actions`](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/automate-with-actions). Accessed 2026-04-26. +- [`docs.github.com — SDK and CLI compatibility`](https://docs.github.com/en/copilot/how-tos/copilot-sdk/troubleshooting/sdk-and-cli-compatibility). Accessed 2026-04-26. +- [`docs.github.com — OpenTelemetry (SDK observability)`](https://docs.github.com/en/copilot/how-tos/copilot-sdk/observability/opentelemetry). Accessed 2026-04-26. +- [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) — open feature request: structured-output flags (`--output-format json` / `stream-json`). **Confirms the CLI does *not* yet support structured event-stream output.** Accessed 2026-04-26. +- [`../squad/README.md` § Watch Mode — Ralph's Automated Polling](../../../../squad/README.md) — Ralph daemon docs. Accessed 2026-04-26. +- [`apps/cli/src/agent/json-event-emitter.ts`](../../../apps/cli/src/agent/json-event-emitter.ts) — Roo's CLI event-stream implementation for the comparison. Accessed 2026-04-26. + +### Findings (2026-04-26) + +#### 12.1 ⚠️ Correction to Phase-5a stub: structured JSON output is NOT shipped + +The Phase-5a § 3.4 table claimed `--output-format=text|json` emits NDJSON events. **Re-verified against the canonical [programmatic reference](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-programmatic-reference) and the [quickstart](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/quickstart): no `--output-format` / `--json` / `--jsonl` flag is documented for the CLI today.** The standing feature request is [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) (still open at access time), which explicitly references Claude Code's `--output-format stream-json` and Codex CLI's `--json` as the prior art being requested. + +The CLI's headless output today is **plain text** (the model's final answer prose) plus session-chrome on stderr. Programmatic consumers are expected to either: +1. Strip chrome with `-s`/`--silent` and treat the prose as the result (as in the canonical quickstart's `result=$(copilot -p '…' -s)` pattern), or +2. Use `--share=PATH` to dump a Markdown transcript and parse that, or +3. Adopt the **SDK** (`@github/copilot-sdk`) and subscribe to its `streaming-events` channel for structured events — see [SDK streaming events doc](https://docs.github.com/en/copilot/how-tos/copilot-sdk/use-copilot-sdk/streaming-events). The SDK is the only first-party path to a structured event stream right now. + +**Filed as Q-042** (track [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52); update Phase-6 Gap Catalog when it ships). For the Phase-7 path-selection decision, this is **a meaningful CLI minus**: any CI consumer that wants per-event hooks, per-tool latency metrics, or live progress streaming must drop down to the SDK rather than wrap the binary. + +#### 12.2 Headless flags — full catalogue (verified) + +Sourced from the [programmatic reference](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-programmatic-reference), the [command reference § Command-line options](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#command-line-options), and the [run-cli-programmatically how-to](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically): + +| Flag | Purpose | Notes | +|---|---|---| +| `-p, --prompt ` | One-shot prompt; CLI exits after the model completes. | If a prompt is also piped on stdin, **stdin is ignored** (`-p` wins). | +| `-s, --silent` | Suppress session metadata and chrome; emit only the final answer. | Required for clean variable capture in scripts. | +| `--no-ask-user` | Disable the `ask_user` interactive tool so the model cannot stall waiting for input. | Recommended for any unattended invocation. | +| `--allow-tool=PATTERN` | Repeatable; expand allowed-tool set using the `Kind(arg)` syntax (e.g., `shell(git:*)`, `write(./src/**)`, `url(github.com)`). | The narrow-permission pattern the docs lead with. | +| `--allow-url=URL` | Pre-approve specific URL targets. | Convenience over `--allow-tool='url(…)'`. | +| `--deny-tool=PATTERN` | Repeatable; expand denied-tool set. | **Deny wins over allow** when both match. | +| `--allow-all-tools` | ⚠️ Allow every tool, including `shell(*)`. | Sandbox-only. | +| `--allow-all-paths` | Loosen path scope. | Pair with `--allow-tool='write'`. | +| `--allow-all-urls` | Loosen URL scope. | Disables the SSRF allowlist. | +| `--yolo` | Equivalent to all three "all" flags. | Not for CI. | +| `--mode=plan\|interactive\|autopilot` | Pin a mode. | Defaults to `interactive`. | +| `--max-autopilot-continues=N` | Cap auto-iterations in autopilot mode (default ~25). | Roo has no equivalent. | +| `--model=` | Override default model (`claude-sonnet-4.5`). | `auto`, `claude-opus-4.7`, `gpt-5`, `gpt-5.2-codex` documented. | +| `--agent=` | Boot the session under a specific custom agent. | See § 5. | +| `--config-dir=` | Per-invocation `COPILOT_HOME` override. | The portability hook. | +| `--additional-mcp-config=JSON\|@file` | Session-only MCP server definitions. | See § 9. | +| `--add-dir=` | Add a workspace root (multi-repo). | Repeatable. | +| `--cwd=` | Run as if invoked from a different directory. | Useful in CI to avoid `cd && copilot` chains. | +| `--resume ` | Non-interactive resume of a previous session. | Pairs with the FTS5 session index from § 3.5. | +| `--continue` | Resume the most recent session in the current cwd. | Sugar for `--resume `. | +| `--share=PATH` | Export the session transcript to Markdown after non-interactive completion. | Default file: `./copilot-session-.md`. | +| `--share-gist` | Publish the transcript as a secret GitHub gist. | ⚠️ Not available to Enterprise Managed Users or `*.ghe.com` data-residency tenants. | +| `--disable-builtin-mcps` | Disable all built-in MCP servers (`github-mcp-server`, `playwright`, `fetch`, `time`). | See § 9. | +| `--disable-mcp-server ` | Disable a single MCP server. | Repeatable. | +| `--no-color` | Strip ANSI from chrome (chrome is on stderr). | Pairs with `-s` for log-friendly output. | +| `-h, --help` / `--version` | Standard. | `--version` prints CLI + bundled SDK + Node versions. | + +> ⚠️ Two options claimed in the Phase-5a § 3.4 stub were **not** confirmable in the current canonical reference at access time and are flagged for re-verification against the live `copilot --help` output: `--output-format=…` (definitively absent — see § 12.1) and the long form `--silent` (the docs use only `-s` and `--silent` interchangeably; both work). All other flags above survive verification. + +#### 12.3 Exit codes + +The canonical references treat exit codes briefly. Confirmed semantics from the [programmatic reference](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-programmatic-reference) plus the [run-cli-programmatically conditional examples](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically#use-in-a-conditional): + +| Exit code | Meaning | +|---|---| +| `0` | Success — the model produced a final answer (note: *the answer's correctness is not verified by the CLI*; downstream `grep`/`jq` is the user's responsibility). | +| `non-zero` | Authentication failure, tool-permission denial under `--no-ask-user`, network/MCP failure, context-cap exceeded with no producible answer, or signal-terminated. | + +The granular non-zero space (e.g., distinguishing auth-fail from permission-deny) is **not documented**. CI consumers that need to distinguish should parse stderr or rely on the `--share=PATH` Markdown transcript, since exit code 1 is overloaded. **Filed as Q-043.** + +#### 12.4 Long-running daemon patterns — Squad's Ralph + +Squad's Ralph daemon is the production-tested example of a long-running CLI driver, documented in [`../squad/README.md` § Watch Mode](../../../../squad/README.md). The CLI primitives that make Ralph possible are **a small, well-defined set**: + +1. **`-p ` (or `-p ` via shell substitution).** Ralph builds a context snapshot Markdown file per round (issue list, squad state, recent decisions) and feeds it as the prompt. > "Ralph builds a context snapshot … writes this context to a temp file using the `-p ` flag … invokes the agent with that file: `gh copilot -p context.md`" — squad README. +2. **`--agent` (custom-agent boot).** Ralph defaults to the squad coordinator (`copilot --agent squad`); the `--agent-cmd` shell-level swap allows the user to point at any binary that accepts `-p`. +3. **Per-invocation isolation via fresh sessions.** Each Ralph round launches a brand-new `copilot` process (no `--resume`); state lives in `.squad/log/` and `.squad/agents//history.md` rather than in the CLI's session store. This avoids the "session got too big" failure mode that auto-compaction would otherwise eventually hit. +4. **Sentinel-file shutdown.** Ralph watches for `.squad/ralph-stop`; on detection it finishes the current round and exits. The CLI does not need to know about the sentinel — process-level wrapping is sufficient. + +> ⚠️ **Important nuance.** Ralph's **default `--agent-cmd` is `gh copilot`** — the legacy GitHub CLI extension, not the agentic `@github/copilot` CLI that is the migration target. Squad's docs predate the GA of the new CLI and rely on the user passing `--agent-cmd "copilot"` to actually invoke the agentic binary. For vault adoption, document this explicitly: `squad watch --execute --agent-cmd "copilot" --copilot-flags "--allow-all-tools --no-ask-user --agent squad"`. + +The takeaway: the CLI does **not** need a daemon mode of its own — the user's process-supervisor (Ralph here, but also `pm2`, `systemd`, a Windows Scheduled Task, or a GitHub Actions cron workflow) does the watching and re-launches `copilot -p …` per work item. The CLI's job is only to be cheap to spawn and to respect `--no-ask-user` so it never blocks indefinitely. + +#### 12.5 CI recipes + +**A. GitHub Actions step.** From the [run-cli-programmatically doc § CI/CD integration](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically#cicd-integration): + +```yaml +- name: Generate test coverage report + env: + COPILOT_GITHUB_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + run: | + copilot -p "Run the test suite and produce a coverage summary" \ + -s --allow-tool='shell(npm:*), write' --no-ask-user +``` + +The `automate-with-actions` doc also documents the `github/copilot-cli-action` reusable action for one-line setup. **Authentication note:** the action expects either `COPILOT_GITHUB_TOKEN` (fine-grained PAT with the `Copilot Requests` permission) or a federated OIDC token; the default `${{ secrets.GITHUB_TOKEN }}` is *not* sufficient for Copilot CLI auth (different permission scope). + +**B. Pre-commit hook (review staged diff).** A `.git/hooks/pre-commit` (or [`pre-commit`](https://pre-commit.com/) framework) snippet: + +```bash +#!/usr/bin/env bash +diff=$(git diff --cached) +[ -z "$diff" ] && exit 0 +verdict=$(printf '%s' "$diff" | copilot -p 'Review the staged diff for obvious bugs or security issues. \ + Reply only OK or ISSUES with one-line summary.' -s --no-ask-user --allow-tool='read') +echo "$verdict" +echo "$verdict" | grep -qi '^OK' || { echo "Refusing commit: $verdict"; exit 1; } +``` + +The Windows / `pwsh` equivalent works the same way against `git diff --cached | copilot …`. + +**C. Watch-mode for issue triage (Ralph-style, pure Bash).** The minimal recipe behind Ralph, no Squad required: + +```bash +#!/usr/bin/env bash +while true; do + gh issue list --label 'triage' --json number,title \ + | copilot -p 'For each issue, classify as bug/feature/docs and suggest the right label. Apply labels via gh issue edit.' \ + --allow-tool='shell(gh:*), read' --no-ask-user -s + sleep 300 # 5-minute poll + [ -f ./ralph-stop ] && exit 0 +done +``` + +#### 12.6 Comparison to Roo's `apps/cli` event emitter + +Roo's CLI ([`apps/cli/`](../../../apps/cli)) is **architecturally distinct** from Copilot's: it spawns a headless VS Code extension host, IPCs to it, and re-emits the extension's `ClineMessage` stream as a structured NDJSON or final-JSON envelope via [`apps/cli/src/agent/json-event-emitter.ts`](../../../apps/cli/src/agent/json-event-emitter.ts) (905 lines; `JsonEventEmitter` class). Concretely: + +| Axis | Roo `apps/cli` | Copilot CLI | +|---|---|---| +| **Process model** | Headless extension host + IPC client | Self-contained Node binary (no extension host) | +| **Output modes** | `"json"` (single accumulated envelope) and `"stream-json"` (NDJSON deltas) — see [`json-event-emitter.ts:7-15`](../../../apps/cli/src/agent/json-event-emitter.ts:7) | Plain text only today; structured-output flag is open feature request [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) | +| **Event types emitted** | `system:init`, `assistant`, `thinking`, `user`, `tool_use` (sub: `tool`/`command`/`mcp`), `tool_result`, `error`, `result`, `control`, `queue`. Schema versioned via `schemaVersion` + `protocol` fields in `system:init` (see [`json-event-emitter.ts:158-166`](../../../apps/cli/src/agent/json-event-emitter.ts:158)). Delta-aware: `previousContent` map computes per-message append-only deltas (`computeDelta`, [`:231-240`](../../../apps/cli/src/agent/json-event-emitter.ts:231)) and structured deltas for tool-use snapshots (`computeStructuredDelta`, [`:250-294`](../../../apps/cli/src/agent/json-event-emitter.ts:250)). | None as a binary surface; the **SDK** exposes streaming events ([Streaming events doc](https://docs.github.com/en/copilot/how-tos/copilot-sdk/use-copilot-sdk/streaming-events)) but the binary does not pipe them. | +| **Sequence guarantees** | Stream-mode: `done: true` flag closes a logical message; reasoning streams use a `+1_000_000_000` key offset to avoid collision with text deltas ([`:91-92`](../../../apps/cli/src/agent/json-event-emitter.ts:91)); cost summary attached to terminal `result` event ([`:780-802`](../../../apps/cli/src/agent/json-event-emitter.ts:780)). | n/a (no event stream); transcripts are post-hoc Markdown via `--share`. | +| **Cost / token reporting per call** | Yes, parsed from `api_req_started` and attached to `result` events. | No (only the user's account-level dashboard). | +| **Headless invocation idiom** | `node ./apps/cli/dist --json` (or `--stream-json`) | `copilot -p "…" -s --allow-tool='…' --no-ask-user` | + +**Migration implication for the vault:** any vault automation today that invokes `node ./apps/cli/dist …` and parses NDJSON events must, on the CLI side, **either** (a) drop down to `@github/copilot-sdk` for equivalent structured streaming, or (b) accept text-only `copilot -p` output and lose per-tool / per-token telemetry. This is the **single largest CLI scripting gap** versus Roo: Roo's `apps/cli` was purpose-built for programmatic consumption; Copilot CLI's `-p` mode prioritises human-readable terminal output and treats automation as the secondary use case. **Filed as Q-042 (above) and updates the CLI gap catalog: G-6 (no structured event stream) is a new 🟠 *major* gap on the CLI path that Phase 6 should adopt.** + +#### 12.7 OpenTelemetry / observability + +Per the [CLI command reference](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference) and the [SDK observability doc](https://docs.github.com/en/copilot/how-tos/copilot-sdk/observability/opentelemetry): + +> "Copilot CLI can export traces and metrics via OpenTelemetry (OTel), giving you visibility into agent interactions, LLM calls, tool executions, and token usage." — CLI command reference + +OTLP export is configured via the standard env vars (`OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_HEADERS`, etc.); no CLI-specific flag is documented. This is a strict win versus Roo's `apps/cli`, which has no OTel surface — and it partially mitigates G-6 (§ 12.6) for users who only need *aggregate* metrics rather than raw event streams. + +--- + +## 13. Limits / known gaps relative to Roo (CLI Gap Catalog — Phase 5b-ii-B-2) + +### Sources + +- All sections above (§§ 0–12). No new external research; this is a pure synthesis closing Phase 5. +- Phase-4 Gap Catalog in [`40-copilot-chat-research.md` § 8](40-copilot-chat-research.md#8-limits--known-gaps) for format mirroring and G-/W- ID reuse. + +### Findings (2026-04-26) — CLI Gap Catalog + +Format mirrors the Phase-4 Gap Catalog. **G-** / **W-** IDs reuse Chat-side identifiers when a gap/win carries over. **CG-** / **CW-** IDs are new and CLI-specific. Severity legend: 🔴 blocker · 🟠 major · 🟡 minor · ✅ closed-on-CLI · 🟢 net win. + +#### Part A — Inherited from Chat (cross-reference G-1…G-14) + +| ID | Title | CLI severity | Chat severity (ref) | Why it carries over / how the CLI mitigates | +|---|---|---|---|---| +| **G-1** | Per-mode file-glob edit restriction (`fileRegex`) | **🟠 major** | 🔴 blocker | The `.agent.md` schema still has no `fileRegex`/`applyTo` for `edit`. **§ 10.6 verdict:** the CLI's `preToolUse` hook closes G-1 for **serial main-agent flows** (working PowerShell drop-in in § 10.4) but **not for `task`-dispatched sub-agents** ([`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392)) and leaks under parallel calls ([`copilot-cli#2893`](https://github.com/github/copilot-cli/issues/2893)). Demoted from blocker to major on the CLI; remains blocker on Chat. | +| **G-2** | Per-mode rules folder (`.roo/rules-/`) | 🟠 major | 🟠 major | Same root cause as Chat (instructions are file-glob-scoped via `applyTo:`, not agent-scoped). Same workaround: inline into the `.agent.md` body, or Markdown-link `.instructions.md` files from the body (§ 4.3). | +| **G-3** | Workspace-scoped tool sets (`*.toolsets.jsonc`) | **N/A** | 🟠 major | The CLI has no toolsets concept; per-agent tool allowlisting is done directly in `.agent.md` `tools:` (workspace-scoped via `.github/agents/`). The Chat-only blocker disappears entirely. | +| **G-4** | Sequential-only `new_task` orchestration | 🟡 minor | 🟡 minor | Same as Chat: `task` sub-agents are parallel-capable; sequential-only is prose-discipline only (§ 3.7, § 8 mapping row). | +| **G-5** | Native webview UI | 🟠 major | 🟡 minor | Worse on the CLI: there is **no GUI at all** for mode/MCP/rule editing (TTY only). See CG-1 below — the CLI accepts this trade-off intentionally. | +| **G-6** | Multi-thread chat sessions per workspace | ✅ better | ✅ better | The CLI ships `--continue` / `--resume` / `--resume ` plus FTS5 session search (§ 3.5). Comparable-or-better to Chat's multi-session UX, just terminal-driven. | +| **G-7** | 128-tool-per-request hard cap | 🟡 minor | 🟡 minor | Carries over (CLI uses the same model-side tool-count limit). Per-agent `tools:` allowlists keep counts low; same mitigation as Chat. | +| **G-8** | Settings Sync coverage gaps | **✅ closed** | 🟡 minor | The CLI uses files under `~/.copilot/` (or wherever `COPILOT_HOME` points). Vault portability via `COPILOT_HOME` (Q-008) sidesteps Settings Sync entirely. | +| **G-9** | Chat-history portability / export | 🟡 minor | 🟠 major | The CLI's `session-state//` is plain JSONL + Markdown plan + checkpoints — trivially backed up with `xcopy`/`tar`. Materially better than Chat's profile-scoped DB (§ 2.2). | +| **G-10** | Custom approval policies per tool / MCP | ✅ better | ✅ better | The CLI's `Kind(arg)` allow/deny grammar (§ 3.3) plus per-invocation `--allow-tool`/`--deny-tool` is already first-class; both surfaces "win". | +| **G-11** | Multi-profile vault automation | **✅ closed** | 🟡 minor | The CLI has no "profile" concept; `COPILOT_HOME` (single env var) replaces the Chat profile-id symlink dance entirely. | +| **G-12** | Sub-agent return is a structured payload | 🟡 minor | 🟡 minor | Same as Chat: `task` returns the sub-agent's final assistant message as free-form text. Workaround: prompt sub-agent to return a JSON block. | +| **G-13** | Local model providers (per-key BYOK) | **✅ closed** | 🟠 major | **Resolved on the CLI path** (§ 7.2 / § 8): `COPILOT_PROVIDER_BASE_URL` / `COPILOT_PROVIDER_TYPE` (openai/azure/anthropic) / `COPILOT_PROVIDER_API_KEY` / `COPILOT_MODEL`. Ollama via OpenAI-compat endpoint works. | +| **G-14** | Sandboxing on Windows | 🟡 minor | 🟡 minor | The CLI inherits the same Windows-platform limitation (no `sandbox`/`sandboxEnabled` honoured); no regression vs Roo. | + +**Inherited tally (CLI):** G-1 demoted to 🟠; G-2 / G-5 / G-9 stay 🟠 (G-5 worse, G-9 better); G-3 / G-8 / G-11 / G-13 either N/A or **closed**; the rest stay 🟡 / ✅. Net: **2 of the Chat catalog's 4 majors are erased on the CLI**, and **the lone 🔴 is demoted to 🟠** (with caveats). + +#### Part B — CLI-specific gaps (CG-1…CG-15) + +| ID | Title | Severity | Description / workaround | +|---|---|---|---| +| **CG-1** | No webview UI for mode/MCP/rule CRUD | 🟠 | Mode and MCP editing is *file editing + slash commands* (`/agent`, `/mcp`, `/skills`, `/instructions`). UX regression vs Roo's `ModesView.tsx` for non-terminal-comfortable users; acceptable for the target audience. Cross-reference G-5 (worse on CLI). | +| **CG-2** | Process-env-only secrets for MCP | 🟡 | No keychain integration like Chat's `${input:…}` Credential-Manager prompt; the OS keychain is reserved for the GitHub auth token (§ 9.3, Q-033). Recommended Windows pattern: `[Environment]::SetEnvironmentVariable("KEY","val","User")`. | +| **CG-3** | `mcpServers` vs `servers` schema fork | 🟡 | A given MCP server requires two configs — one for `.vscode/mcp.json` (`servers:` + `inputs:`) and one for `mcp-config.json`/`.github/mcp.json` (`mcpServers:` + `${VAR}`). Documented one-line `jq` migration in § 9.1; vault must pick a canonical source and generate the other. | +| **CG-4** | Repo-layer `settings.json` 6-key allowlist | 🟠 | Only `companyAnnouncements`, `disableAllHooks`, `enabledPlugins`, `extraKnownMarketplaces`, `hooks`, `mergeStrategy` are honoured at repo scope; vault `allowedTools` / `deniedTools` / `systemPrompt` overrides are silently dropped (§ 10.5, Q-032). Mitigated by user-scope settings or per-invocation flags / per-agent inlining. | +| **CG-5** | Sub-agent depth & concurrency caps | 🟡 | Default sub-agent depth = 6, concurrency = 32 (§ 5.1). Likely sufficient for vault patterns (single-level + sequential), but nested orchestrators must be tested before production (Q-034). | +| **CG-6** | Windows hook latency unknown | 🟡 | `pwsh -NoProfile -Command …` cold-start is ~150–400 ms typical, >1 s with module loads (§ 10.4). Adds visible lag on tool-heavy turns; needs empirical measurement on the user's box (Q-039) before recommending hook-heavy policies. | +| **CG-7** | No structured `--output-format=json` / `stream-json` | 🟠 | Confirmed absent ([`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52); § 12.1, § 12.6, Q-042). Roo's `apps/cli` emits 28+ typed NDJSON event types via [`json-event-emitter.ts`](../../../apps/cli/src/agent/json-event-emitter.ts); Copilot CLI is plain-text only. **Mitigated** by (a) `@github/copilot-sdk` streaming events for code-driven consumers and (b) OTel for aggregate metrics. The single largest scripting gap vs Roo. | +| **CG-8** | SDK is 0.x alpha with ~monthly minor breaks | 🟠 | 54 versions in ~5 months; *"minor breaking changes may still occur between releases"* (§ 7.6, Q-046). Squad ships an ESM patcher and an adapter mirror layer to survive the churn; any Path-D VSIX consuming the SDK directly inherits the same maintenance burden. | +| **CG-9** | Skill `allowed-tools: shell` security risk | 🟡 | Skills can pre-approve `shell` / `bash` to skip per-call confirmation (§ 11.2). Bypasses the approval flow that is otherwise the CLI's primary safety net. Policy: **never enable for unreviewed third-party skills**; document in vault Phase-8 playbook. | +| **CG-10** | No GUI for `/mcp` / `/agent` / `/skills` / `/instructions` | 🟡 | Slash-command-only management; intentional CLI design choice but a real gap vs Roo's webview pickers. Cross-references CG-1; severity is split because slash commands are cheap to learn even when no GUI exists. | +| **CG-11** | Sub-agent `preToolUse` bypass | 🟠 | [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) — `task`-dispatched sub-agents leak past hook policies. **The binding constraint on G-1's CLI mitigation** (§ 10.6). Mitigated today by using `--agent` boot mode for restriction-sensitive workflows and explicitly forbidding sub-agent dispatch in agent bodies that need file-regex enforcement. | +| **CG-12** | Squad alpha v0.9.1 production risk | 🟠 (Path-C only) | Squad pin is `^0.1.32` of `@github/copilot-sdk` (3 minors behind current 0.3.0); Squad itself is alpha (Q-011). Material production risk if you build on Squad's orchestration layer; **N/A** for Path-A (Chat) or Path-B (CLI built-ins only). | +| **CG-13** | Active agent name not in hook payload | 🟡 | `preToolUse` payload has `toolName`, `toolArgs`, `cwd`, `sessionId`, `timestamp` — no `agentName` / sub-agent depth (Q-037). Per-mode `fileRegex`-equivalent must thread the agent identity via a sidecar state file written from `subagentStart`; reference impl in § 10.4. | +| **CG-14** | Plugin-defined `preToolUse` hooks don't fire | 🟡 | [`copilot-cli#2540`](https://github.com/github/copilot-cli/issues/2540) — only repo + user hooks reliably fire; plugin-shipped hooks are silently dropped. Mitigation: ship the vault's `fileRegex`-equivalent as a repo or user hook, never as a plugin. | +| **CG-15** | `modifiedArgs` / `updatedInput` not honoured | 🟡 | [`copilot-cli#2013`](https://github.com/github/copilot-cli/issues/2013) — docs list a `modifiedArgs` output field for `preToolUse`, but the CLI ignores it. Hooks can only allow/deny, not rewrite (e.g., re-route writes to a quarantine dir). Pure deny-or-allow policy semantics on the CLI today. | + +**CG- tally:** 5 × 🟠, 9 × 🟡, 1 × 🟠 (Path-C-only). Notably **zero 🔴 blockers** — every CLI-specific gap has a documented workaround. + +#### Part C — CLI-specific wins (CW-1…CW-12) + +| ID | Title | Severity | One-line summary | +|---|---|---|---| +| **CW-1** | `preToolUse` hook = the only ergonomic place to enforce `fileRegex` | 🟢 | Closes G-1's worst-case impact for serial main-agent flows; § 10.4 PowerShell drop-in is the reference impl. | +| **CW-2** | BYOK provider env vars (Ollama / Anthropic / Azure) | 🟢 | Closes G-13 entirely — the Chat path's 🟠 major becomes ✅ on the CLI. | +| **CW-3** | Headless `-p` + OpenTelemetry for CI/CD | 🟢 | Even without `--output-format=json`, OTel gives traces / metrics / token-usage observability that Roo's `apps/cli` does not have (§ 12.7). | +| **CW-4** | `--resume` with FTS5 session search | 🟢 | Durable conversational memory across invocations; full-text search across events and plan files (§ 3.5). | +| **CW-5** | Skills as executable Markdown | 🟢 | Strict additive over Roo's mode/rule split — a skill bundle (`SKILL.md` + helper script) is reusable across agents and loaded on-demand (§ 11.6). | +| **CW-6** | `COPILOT_HOME` portability | 🟢 | Single env var redirects all CLI state (settings, agents, skills, instructions, hooks, MCP, sessions). Vault portability becomes trivial vs Chat's per-profile-id symlink dance (resolves Q-008; closes G-11). | +| **CW-7** | Squad rides natively here | 🟢 (Path-C) | If the user wants parallel orchestration / Ralph daemon, the CLI is the only path — Squad has no `vscode.lm` dependency (Q-010). | +| **CW-8** | `defineTool` in `@github/copilot-sdk` | 🟢 | Zod-typed custom tools without writing a VSIX — Path-D-lite for Node-script users (§ 7.2). | +| **CW-9** | Programmatic `SessionHooks` in the SDK | 🟢 | Six lifecycle callbacks (`onPreToolUse`, `onPostToolUse`, `onUserPromptSubmitted`, `onSessionStart`, `onSessionEnd`, `onErrorOccurred`) for CI/CD orchestrators — file-based hook parity, in-process (§ 7.2). | +| **CW-10** | Lower per-invocation latency than VS Code Chat | 🟢 | No extension-host startup; `copilot -p …` is a single Node spawn — measurably faster cold-start for one-shot CI work. | +| **CW-11** | Auto-compaction at ~95% context | 🟢 | "Infinite sessions" — no manual `/clear` ever required (§ 3.5); Roo has no equivalent. | +| **CW-12** | First-class permission grammar (`Kind(arg)` allow/deny) | 🟢 | `--allow-tool='shell(git:*)'`, `--deny-tool='shell(git push)'`, deny-wins semantics (§ 3.3). Finer-grained and more pinnable than anything Roo or Chat ships out of the box. | + +**CW- tally:** 12 wins (10 universal + 2 path-specific). Compares to Chat's W-1…W-12 (12 wins) — **the CLI matches Chat's win count while closing 3 of Chat's gaps outright** (G-3 / G-11 / G-13) and **demoting the lone Chat blocker** (G-1 🔴 → 🟠). + +#### Part D — Net verdict + +**Headline severity tally.** CLI-side gaps total **5 × 🟠 + 10 × 🟡** (including G-2/G-5 inherited and CG-1…CG-15), with **zero 🔴 blockers**. Chat-side, by contrast, carried **1 × 🔴 + 4 × 🟠 + ~6 × 🟡** (Phase 4d net assessment). Adjusting for the items the CLI actually closes — G-3 (N/A), G-8 / G-11 / G-13 (✅) — **the CLI eliminates one blocker and three majors that Chat carries**, while introducing four new majors of its own (CG-1 webview-UI loss, CG-4 repo-allowlist scope, CG-7 no structured output, CG-8 SDK churn, CG-11 sub-agent hook bypass). On wins, both paths ship 12 entries; the CLI's CW-1 through CW-6 are *materially harder to replicate on Chat* (hook enforcement, BYOK, OTel, skills, portability) while Chat's W-1 through W-12 are mostly UX-and-marketplace conveniences that the CLI deliberately forgoes. **Net structural severity is lower on the CLI path** — fewer absolute blockers, fewer dependency-blocking unknowns, and a clearer escape hatch for every remaining major (hooks for G-1, env vars for G-13, file backups for G-9, slash commands for CG-1). + +**Path-specific recommendation preview (feeds Phase 7).** The CLI is the natural choice for **DevOps, CI-heavy, parallel-orchestration, and BYOK-dependent users** — anyone who scripts agentic work, runs Ralph-style watch loops, hosts non-Copilot models locally, or values vault portability via `COPILOT_HOME` over Chat's profile-id machinery. The **interactive coding, multi-profile, and GUI-comfortable audiences** are still better served by Chat — `ModesView`-style affordances, checkpoint UX, fork-conversation, and the unified chat panel have no CLI counterparts and never will. **The two paths are complementary, not competing** — Phase 7 should preserve the option to run both in parallel (same `.agent.md` files work in both, same `AGENTS.md`, same MCP servers via the documented schema fork) and let the user pick the surface per workflow. Squad (Path C) layers on top of the CLI only and is gated on accepting CG-12's alpha-stability risk; Path D (vault-as-VSIX) is 🟡 embeddable but inherits CG-8's monthly SDK-churn tax (§ 7.5). + +**Open risks worth tracking upstream.** The three highest-leverage issues to file/test/track before committing to a CLI-first migration: + +1. **[`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) — sub-agent `preToolUse` bypass (CG-11).** This is the single biggest threat to the G-1 mitigation. Until it ships, the vault must avoid `task`-dispatched sub-agents in restriction-sensitive workflows or accept that `fileRegex` is unenforced once the orchestrator delegates. +2. **[`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) — structured `--output-format=json` / `stream-json` (CG-7, Q-042).** When this lands, the CLI matches Roo's `apps/cli` for CI integration and the SDK fall-back becomes optional rather than required. Phase-6 Gap Catalog should be revisited. +3. **Q-039 — empirical `pwsh` cold-start latency on the user's Windows 11 box (CG-6).** Trivial to measure (`Measure-Command { 1..20 | % { pwsh -NoProfile -Command 'exit 0' } }`), but it sizes the cost ceiling for the entire hook-based G-1 mitigation. Worth running before Phase 8 commits to a hook-heavy playbook. + +Honourable mentions tracked but lower-leverage: [`copilot-cli#2893`](https://github.com/github/copilot-cli/issues/2893) (parallel-call hook race), [`copilot-cli#2540`](https://github.com/github/copilot-cli/issues/2540) (plugin hook bug, CG-14), [`copilot-cli#2013`](https://github.com/github/copilot-cli/issues/2013) (`modifiedArgs` ignored, CG-15), and Q-046 (CLI binary bundling for Path-D VSIX). + +--- + +## Cross-links + +- [`00-plan.md`](00-plan.md) · [`30-squad-inventory.md`](30-squad-inventory.md) · [`40-copilot-chat-research.md`](40-copilot-chat-research.md) · [`60-gap-analysis.md`](60-gap-analysis.md) · [`90-decision-log.md`](90-decision-log.md) · [`99-open-questions.md`](99-open-questions.md) diff --git a/docs/investigation/roo-to-copilot/60-gap-analysis.md b/docs/investigation/roo-to-copilot/60-gap-analysis.md new file mode 100644 index 00000000000..4f50d8a7e29 --- /dev/null +++ b/docs/investigation/roo-to-copilot/60-gap-analysis.md @@ -0,0 +1,266 @@ +--- +phase: 6 +status: complete +owner: architect-synthesis-subtask +last_updated: 2026-04-26 +sources: + - docs/investigation/roo-to-copilot/10-roo-inventory.md + - docs/investigation/roo-to-copilot/20-roo-vault-inventory.md + - docs/investigation/roo-to-copilot/30-squad-inventory.md + - docs/investigation/roo-to-copilot/40-copilot-chat-research.md + - docs/investigation/roo-to-copilot/50-copilot-cli-research.md + - docs/investigation/roo-to-copilot/99-open-questions.md +--- + +# Phase 6 — Unified Gap Analysis Matrix + +> Parent plan: [`00-plan.md`](00-plan.md) · Index: [`README.md`](README.md) + +## A. Methodology / Reading Guide + +**Question this file answers.** For every Roo-Code feature catalogued in [`10-roo-inventory.md`](10-roo-inventory.md) (and the vault patterns in [`20-roo-vault-inventory.md`](20-roo-vault-inventory.md)), what is the closest equivalent — or the explicit gap — in (i) GitHub Copilot Chat (VS Code), (ii) GitHub Copilot CLI (`@github/copilot`), and (iii) Squad layered on top of either Copilot surface? + +**Severity legend (per-target cell).** + +- 🔴 **blocker** — no acceptable workaround; would force keeping Roo or accepting a hard loss. +- 🟠 **major** — no first-class equivalent but a workable workaround exists with non-trivial effort. +- 🟡 **minor** — different ergonomics; functionality preserved with prompt/process changes. +- ✅ **parity** — drop-in or near-drop-in replacement. +- ➕ **additive** — Copilot/Squad ships a capability Roo does not have at all. + +**Dual-severity convention.** Each row's *Gap severity* column carries **per-path severities** when Chat and CLI diverge — written as `Chat / CLI ` (e.g., `Chat 🔴 / CLI 🟠` for G-1). When both paths are equivalent, a single icon is used. + +**Squad column convention** (see also § E). The Squad cell expresses **what Squad adds on top of CLI** for that row, not a separate replacement path. Values: `same as CLI` (no delta), `+ ` (additive on Path C only), or `n/a` (Squad has no opinion on that surface). + +**Backref IDs.** Cells reference the source-catalog identifiers rather than restating descriptions: + +- **G-1…G-14, W-1…W-12** — Chat-side Gap Catalog from [`40-copilot-chat-research.md` § Limits / Known Gaps](40-copilot-chat-research.md#limits--known-gaps). +- **CG-1…CG-15, CW-1…CW-12** — CLI-side Gap Catalog from [`50-copilot-cli-research.md` § 13](50-copilot-cli-research.md#13-limits--known-gaps-relative-to-roo-cli-gap-catalog--phase-5b-ii-b-2). +- **Q-NNN** — open questions from [`99-open-questions.md`](99-open-questions.md). +- **`50 § 9.4`** etc. — section anchors in source files. + +Rows are grouped by Roo concept area, in roughly the order of [`10-roo-inventory.md`](10-roo-inventory.md). New gaps discovered during synthesis are tagged `[NEW]` and have a corresponding Q-ID. + +## B. Master Gap Matrix + +### B.1 Modes / agents schema + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| Mode `slug` (`^[a-zA-Z0-9-]+$`) | Filename `.agent.md` under `.github/agents/` | Filename `.agent.md` under `.github/agents/` or `~/.copilot/agents/` | same as CLI | ✅ | Mechanical rename | 40 § Custom Chat Modes; 50 § 5.4 | +| Mode `name` | Frontmatter `name:` (defaults to filename) | Frontmatter `name:` (defaults to filename) | same as CLI | ✅ | — | Identical semantics. | +| Mode `roleDefinition` + `customInstructions` | `.agent.md` body (Markdown, prepended to user turn) | `.agent.md` body (Markdown, prepended to user turn) | same as CLI | ✅ | Concatenate the two Roo fields into one body | 50 § 5.4 mapping table. | +| Mode `whenToUse` (auto-pick hint) | No formal field; `description:` shows hover hint only | No equivalent; agent is selected via `--agent`/`/agent` | same as CLI | 🟡 | Capture intent in `description`; rely on user to pick agent | Roo also doesn't *enforce* `whenToUse`; user picks too. Accept loss. | +| Mode `description` (chat-input placeholder) | Frontmatter `description:` | Frontmatter `description:` (also drives autonomous skill triggering) | same as CLI | ✅ | — | 40 § Custom Chat Modes (1). | +| Mode `source` (`global` / `project`) and precedence (project wins) | Workspace `.github/agents/` overrides user `~/.copilot/agents/` overrides plugin agents | Project `.github/agents/` > user `~/.copilot/agents/` > plugin agents (50 § 5.1) | same as CLI | ✅ | Use the same precedence; built-ins overridable by name | Cleaner than Roo's separate "auto-stamp" of `source`. | +| Built-in modes (architect/code/ask/debug/orchestrator) | No matching built-ins; user re-creates as `.agent.md` | 7 built-ins (`code-review`, `general-purpose`, `explore`, `research`, `rubber-duck`, `task`, `configure-copilot`) | same as CLI | 🟡 | Author 5 vault `.agent.md` files mirroring Roo built-ins; CLI users can also start from built-ins | 50 § 5.1; CLI better-than. | +| Vault layered composition (built-in → global YAML → project `.roomodes`) | Plugin → user → workspace `.github/agents/` (3-tier) | Plugin → user → project (3-tier; same shape) | same as CLI | ✅ | Direct mapping; vault `global-settings/custom_modes.yaml` (21 modes) explodes to 21 `.agent.md` files in the user-scope dir | 20 § Global Settings; 40 § Custom Chat Modes (2). | + +### B.2 Tool restrictions (per-mode tool/MCP/file gating) + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| `groups: [read/edit/command/mcp/modes/browser]` (coarse tool-group ACL) | `.agent.md` `tools:` array (per-tool, finer-grained); `#edit` / `#search` built-in tool sets approximate `edit`/`read` groups | `.agent.md` `tools:` array; group expansion per 50 § 5.4 (`read` → `view`/`grep`/`glob`; `command` → `bash`/`powershell`; `browser` → `web_fetch`) | same as CLI | ✅ (W-stronger) | Mechanical group→tool expansion in the converter | Copilot is **finer-grained** than Roo. | +| `groups[].fileRegex` per-group edit restriction (e.g., architect = `\.md$`) | **No equivalent** in `.agent.md` — G-1 | `preToolUse` hook pattern-matches `toolArgs.path` per CG-1/CW-1 reference impl (50 § 10.4) | + parallel-orchestration *ignores* the policy on `task` dispatch (CG-11) → recommend Squad-disabled when policy critical | **Chat 🔴 / CLI 🟠** | Chat: prose-only ("only edit `.md`"); CLI: PowerShell `preToolUse` policy | **G-1 (headline)**; binding constraint = CG-11 sub-agent bypass; final severity hinges on Q-047. | +| Per-mode `allowedMcpServers: ["github"]` | `tools: ["github/*"]` in `.agent.md` (W-3 directly; resolves Q-002) | `tools: ["github-mcp-server/*"]` plus optional `mcp-servers:` allowlist (50 § 9.4) | same as CLI | ✅ | Direct rename | Both paths are 1:1 with Roo. | +| `allowedMcpServers: []` (empty = "no MCP") | Omit all `/…` from `tools:` | Omit all `/…` from `tools:` | same as CLI | ✅ | Resolves Q-009 | 40 § MCP Support (8); used by vault `code` mode. | +| Per-mode rules folder (`.roo/rules-/`) | No first-class equivalent — G-2; `.instructions.md` is file-glob-scoped (`applyTo:`), not agent-scoped | Same root cause — G-2 inherits | same as CLI | 🟠 | Inline rules into `.agent.md` body, or Markdown-link `.instructions.md` from agent body | Q-018 still tracks the converter design. | +| Vault per-mode `groups[].fileRegex` examples (translate, docs-extractor, architect) | No equivalent; multi-mode loss | `preToolUse` hook table mapping `agentName → regex` (50 § 10.4 prototype) | + Squad's `protected-files` skill could reinforce in prose | **Chat 🔴 / CLI 🟠** | Same as G-1 row | The vault uses `fileRegex` on ≥3 modes (20 § Global Settings); Q-047 quantifies blast radius. | + +### B.3 Custom prompts / rules + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| Project `.roo/rules/*.md` (always-on) | `.github/copilot-instructions.md` + `.github/instructions/*.instructions.md` (with `applyTo:`) | `.github/copilot-instructions.md` + `.github/instructions/**/*.instructions.md` (50 § 4.1) | same as CLI | ✅ | Rename + concatenate | 40 § Custom Instructions; 1:1 cross-tool. | +| Global `~/.roo/rules/*.md` | `%APPDATA%\Code\User\prompts\*.instructions.md` and/or `~/.copilot/instructions/` | `~/.copilot/instructions/*.instructions.md` (follows `COPILOT_HOME`) | same as CLI | ✅ | Vault symlink target switches from `~/.roo/rules/` to `~/.copilot/instructions/` | 40 § Storage Locations; 50 § 2.2. | +| Per-mode rules `.roo/rules-/` | G-2 (no per-agent rules folder) | G-2 inherits | same as CLI | 🟠 | Inline into agent body; Q-018 | See B.2 also. | +| `AGENTS.md` (always-on, project root) | Native — `chat.useAgentsMdFile` default on (W-5) | Native — read from workspace root (50 § 4.1) | same as CLI | ✅ | 1:1 | Cross-tool standard. | +| `AGENTS.local.md` (gitignored personal layer) | Read by VS Code (`AGENTS.local.md` listed alongside `AGENTS.md`) | Read by CLI (`Copilot.md` / `CLAUDE.md` / etc. compatible — verify suffix `.local.md` mapping in Q-048) | same as CLI | 🟡 (verify) | Test on conversion | `[NEW]` Q-048 — unconfirmed `AGENTS.local.md` suffix support on CLI. | +| Subfolder `.roo/` discovery (`enableSubfolderRules`) | Nested `AGENTS.md` behind `chat.useNestedAgentsMdFiles` (experimental); nested `.instructions.md` discovery via `chat.instructionsFilesLocations` | Nested instructions via `**` glob in `applyTo:` | same as CLI | 🟡 | Use `applyTo:` globs | Roo Q-007 also still open on the production default. | + +### B.4 MCP integration + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| Global MCP config (Win: `…\globalStorage\…\mcp_settings.json`) | `%APPDATA%\Code\User\mcp.json` (Default profile) or `%APPDATA%\Code\User\profiles\\mcp.json` (named) | `~/.copilot/mcp-config.json` (follows `COPILOT_HOME`) | same as CLI | ✅ | One-time move + `mcpServers` ↔ `servers` rename for Chat | 40 § MCP (8); 50 § 9.1. | +| Project MCP config (`.roo/mcp.json`) | `.vscode/mcp.json` (committed; `${input:…}` placeholders) | `.github/mcp.json` (canonical) or `.mcp.json` at repo root | same as CLI (Squad uses non-canonical `.copilot/mcp-config.json`) | ✅ | Per-format renames | Resolves Q-031 — Squad's `.copilot/mcp-config.json` is non-canonical (50 § 9.1). | +| Top-level shape (`mcpServers`) | Renamed to `servers:` + top-level `inputs:[]` | Stays `mcpServers:`; no `inputs` array | n/a | 🟡 (CG-3 schema fork) | `jq '{mcpServers: .servers}'` migration | 50 § 9.2; same logical config, two file shapes. | +| stdio transport (`command`/`args`/`env`) | Supported; `envFile` + `sandboxEnabled`/`sandbox` (mac/linux only) extras | Supported; adds `tools:[]` per-server filter, `timeout`, `cwd` | same as CLI | ✅ | Direct mapping | 40 § MCP (1); 50 § 9.2. | +| streamable-http transport | `type: "http"` (preferred) + `headers` (HTTP-stream then SSE fallback) | `type: "http"`, `url`, `headers`, plus `oauthClientId`/`oauthPublicClient`/`oidc` | same as CLI | ✅ (CLI ➕ OAuth) | Use HTTP form on both sides | CLI **adds** OAuth flow for HTTP servers. | +| Inline tokens in `mcp_settings.json` (vault gitignored) | `${input:id}` first-run prompt → Windows Credential Manager (W-4) | **Process-env substitution only** (`${VAR}`); no keychain prompt — CG-2 / Q-033 | + Squad's `secret-handling` skill formalises env-var pattern | **Chat ✅ / CLI 🟡** | Chat uses `${input:…}`; CLI uses `[Environment]::SetEnvironmentVariable("KEY","val","User")` then `${KEY}`; vault must dual-author or pick canonical | 40 § MCP (3); 50 § 9.3. **No shared secret story.** | +| Per-mode MCP allowlist (`allowedMcpServers`) | `.agent.md` `tools: ["server/*"]` | Same plus `.agent.md` `mcp-servers:` to scope server visibility (50 § 9.4) | same as CLI | ✅ | Resolves Q-002 | Both paths beat Roo's coarse per-mode list with per-tool granularity. | +| `disabled: true` per server | Extension-view enable/disable (state stored separately from `mcp.json`) | `/mcp disable ` (per-session); `--disable-mcp-server` (per-invocation); built-ins via `--disable-builtin-mcps` | + Squad does not host MCP itself | ✅ | Choose tier-appropriate primitive | 40 § MCP (8); 50 § 9.5. | +| Per-tool `alwaysAllow` array | Chat dialog "Always allow" per (workspace, tool) + `chat.tools.eligibleForAutoApproval` | `--allow-tool='server(tool)'` / `settings.json` `allowedTools` | same as CLI | ✅ (CW-12) | Both finer than Roo's per-server array | 50 § 3.3. | +| MCP discovery from other clients (Claude Desktop / Cursor / Continue) | `chat.mcp.discovery.enabled` (off by default) — Claude Desktop confirmed; others inferred (Q-025) | No formal discovery; `--additional-mcp-config @file` for ad-hoc imports | n/a | 🟡 | Manual import from vault | 40 § MCP (7). | +| `/mcp` REPL commands | None in Chat (toggles via UI) | `/mcp [show\|add\|edit\|delete\|disable\|enable\|auth\|reload]` (50 § 9.5) | + Squad documents but does not extend | ➕ on CLI | — | CLI is materially better for keyboard-driven MCP ops. | + +### B.5 Orchestrator / sub-agents + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| `new_task(, )` delegation primitive | Built-in `agent` tool (a.k.a. `runSubagent`) + `agents:` frontmatter allowlist | Built-in `task` tool + `.agent.md` `mcp-servers`/`tools` scoping | + Squad `fan-out` / `wave-dispatch` / `fleet-dispatch` (parallel-by-default) | ✅ | Mechanical translation; subagent receives prompt string and returns summary | 40 § Agent Mode (8); 50 § 5.1. | +| Sequential-only enforcement (Roo test-enforced) | Parallel by default; sequential needs prose discipline — G-4 | Parallel by default; same prose-discipline mitigation — G-4 inherits | + Squad **doubles down on parallel** (fan-out is the point) | 🟡 | Parent agent body says "run subagents in this order, await each" | Resolves Q-013; net upside elsewhere (parallel review). | +| Boomerang return shape (structured `attempt_completion` payload) | Subagent's final assistant message becomes a tool result (free-form) — G-12 | Same — G-12 inherits | same as CLI | 🟡 | Prompt subagent: "return JSON with these fields"; orchestrator parses | 40 § Agent Mode (8.4 last row). | +| Subagent recursion / nesting | `chat.subagents.allowInvocationsFromSubagents` (default off); max depth 5 | Default depth 6, concurrency 32 (50 § 5.1) — CG-5 minor caveat | + Squad's casting registry adds named persistence (different model) | ✅/➕ | — | Both paths exceed Roo (which forbids nesting via test). | +| Subagent uses different model from parent | Explicit `model:` param; cost-tier capped to parent's tier | `task(agent="…", model=…)` honours `.agent.md` `model:` | + Squad `model-selection` skill | ➕ | — | Roo cannot do this; pure win. | +| Vault orchestrator demoted to `read`-only (delegation-only guardrail) | Replicate via `tools: ['agent', 'view', 'grep']` in orchestrator `.agent.md` | Same | same as CLI | ✅ | Mechanical | 20 § Notable patterns. | + +### B.6 Native tool surface + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| Read tools (`read_file`, `list_files`, `search_files`, `codebase_search`) | Built-in: `#search`, `read/problems`, `search/codebase`, `search/usages` (W-via tool sets) | Built-in: `view`, `glob`, `grep` (rg-backed), `show_file` (experimental) | same as CLI | ✅ | Group→tool expansion per 50 § 5.4 | Both paths cover Roo's read group. | +| Edit tools (`apply_diff`, `apply_patch`, `edit_file`, `write_to_file`, `search_replace`) | Built-in `#edit` tool set | Built-in `apply_patch`, `create`, `edit` | same as CLI | ✅ | Use `#edit` (Chat) or enumerate `apply_patch`/`create`/`edit` (CLI) | Both cover Roo's edit group. | +| Command execution (`execute_command`, `read_command_output`) | Built-in `runInTerminal`; per-command auto-approve via `chat.tools.terminal.autoApprove` regex map | Built-in `bash` / `powershell` / `bash_list` / `bash_read` / `bash_stop` / `bash_write` (POSIX + PS1 twins) | same as CLI | ✅/➕ | CLI ships full background-job lifecycle (`*_list`/`*_stop`) | 50 § 3.6; richer than Roo. | +| MCP tool synthesis (`__`) | Per-tool entries from `tools:` allowlist; `mcpserver/*` wildcard | Synthetic `()` per MCP-server tool; allowlist via `Kind(arg)` | same as CLI | ✅ | — | 40 § MCP (4); 50 § 3.6. | +| `update_todo_list` always-on tool | No first-class todo tool; can author via `.prompt.md` or skill | No first-class todo tool; same | + Squad `.squad/identity/now.md` is similar shape | 🟡 [NEW] Q-049 | Author a `todo-list.skill` or use Markdown checklist in chat | The reminders surface (Roo re-injects the todo each turn) is **not** replicated by Copilot. | +| 128-tool-per-request hard cap (Roo's 22 native + N MCP stays under) | Hard 128-cap per request — G-7 | Same model-side limit — G-7 inherits | same as CLI | 🟡 | Per-agent `tools:` keeps counts low; enable `github.copilot.chat.virtualTools.threshold` (Chat) | Comfortable today with vault's 4 enabled MCP servers. | + +### B.7 Webview UI / mode editing + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| `ModesView.tsx` (visual mode CRUD with `groups`/`fileRegex` form) | Command Palette + JSON/Markdown editor + Chat Customizations editor (Preview); `Chat: New Agent…` (G-5) | None — TTY only; `/init` scaffolds; `/agent` picker (CG-1) | n/a (Squad has no UI either) | **Chat 🟡 / CLI 🟠** | Edit `.agent.md` directly; consider extension-shipped UI (Path D) | 40 § Chat Participants (5); 50 § 13 CG-1. | +| `McpServerRestriction.tsx` (per-mode MCP picker) | Inline `tools: ["server/*"]` in agent file; no GUI | Inline `tools:` / `mcp-servers:`; no GUI; `/mcp show` lists | n/a | 🟠 | Edit JSON/Markdown | Vault users lose the visual checklist. | +| `DeleteModeDialog.tsx` (with cascade-delete `rules-/`) | Manual file delete; no cascade UX | Manual; `/skills remove ` for skills | n/a | 🟡 | Wrapper PowerShell script | Trivial to recreate; not blocking. | +| Marketplace tab for community modes | Agent Plugins (Preview) gallery; `chat.plugins.enabled` (W-2) | Plugin marketplaces via `extraKnownMarketplaces` | + Squad `plugin marketplace add/list/browse` | ✅/➕ | — | Both paths beat Roo's MarketplaceManager. | +| Context settings (todoListEnabled, autoCondense thresholds, partial-reads toggles) | `chat.checkpoints.enabled`, `chat.editRequests`, `github.copilot.chat.agent.autoFix`, `chat.agent.maxRequests` | `settings.json` cascade (`~/.copilot/settings.json` → repo → local) | same as CLI | ✅/🟡 | Different setting names; one-time mapping | 40 § Agent Mode (2); 50 § 2.3. | + +### B.8 CLI / scripting + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| `apps/cli` headless invocation | None (Chat is GUI-only) | `copilot -p "" -s --no-ask-user --allow-tool='…'` (50 § 12.2) | + Squad `squad watch --execute` Ralph daemon (CW-7 on Path C) | **Chat 🔴-irrelevant / CLI ✅** | Path B native; Path A users must script around the IDE | Headless is a CLI-only path. | +| NDJSON event stream (`json-event-emitter.ts`: 28+ typed events with deltas) | None | **Plain text only**; structured-output flag is feature request [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) — CG-7 / Q-042 | + SDK `session.on(event, …)` (`@github/copilot-sdk` streaming) | **Chat n/a / CLI 🟠** | Drop down to `@github/copilot-sdk` for structured events | Single largest CLI scripting gap vs Roo (50 § 12.6). | +| `--resume` / session history | `Fork Conversation` button + per-workspace session list (no portable export — G-9) | `--continue`, `--resume[=name]`, `/resume`, FTS5 search (CW-4) | + Squad's `.squad/log/` is the persistence | **Chat 🟠 / CLI ✅** | CLI is notably better; Chat sessions are profile-scoped state DB | 40 § Agent Mode (4); 50 § 3.5. | +| `--json` / structured output for CI | None | Absent today (CG-7); SDK or `--share=PATH` Markdown transcript only | + SDK | 🟠 | Same as NDJSON row | Tracked upstream. | +| Exit codes (granular) | n/a | `0` success / non-zero overloaded — CG-7 / Q-043 | same as CLI | 🟡 | Parse stderr or `--share` transcript | 50 § 12.3. | +| OpenTelemetry observability | None | OTLP env-var export (CW-3) — *strict win vs Roo* | + Squad `runtime/otel` wraps the SDK's spans | ➕ | — | 50 § 12.7. | + +### B.9 Settings storage / portability + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| Windows global paths (`%APPDATA%\Code\User\globalStorage\…\settings\…`) | `%APPDATA%\Code\User\prompts\` (global) + profile-scoped `mcp.json`/`settings.json` | `%USERPROFILE%\.copilot\` (or wherever `COPILOT_HOME` points) | same as CLI | ✅/➕ | — | 40 § Storage Locations; 50 § 2.1. | +| `~/.roo/` global rules dir (homedir, NOT VS Code globalStorage) | `~/.copilot/instructions/` and/or `%APPDATA%\Code\User\prompts\` | `~/.copilot/instructions/` (or `${COPILOT_HOME}/instructions/`) | same as CLI | ✅ | Vault symlink retargets | 10 § Settings Storage Paths; resolves Q-008 partially. | +| Settings Sync coverage | "Prompts and Instructions" + "MCP Servers" categories cover most files; `*.toolsets.jsonc` reportedly excluded — G-8 / Q-024 | N/A — uses `COPILOT_HOME`; sync is via git, not VS Code | + Squad commits `.squad/` to git | **Chat 🟡 / CLI ✅** | CLI eliminates the sync question | 40 § Storage Locations; 50 § 2.2. | +| Multi-profile vault automation | `mcp.json`/`settings.json` profile-scoped at `…\profiles\\` — G-11 / Q-026 | No "profile" concept; `COPILOT_HOME` = single env var | n/a | **Chat 🟡 / CLI ✅** | CLI closes G-11 entirely (CW-6) | 50 § 2.1. | +| Vault `setup-vault.ps1` symlink scheme | Works for global `prompts/` folder; per-profile `mcp.json` needs PowerShell helper | Works trivially via `COPILOT_HOME` env var | n/a | **Chat 🟡 / CLI ✅** | Phase-8 owns the helper script | 20 § Setup Scripts; 50 § 6.4. | +| `roo-vault/projects//.roo/` per-project blueprint | `.github/agents/`, `.github/instructions/`, `.vscode/mcp.json`, `AGENTS.md` per project | `.github/agents/`, `.github/instructions/`, `.github/mcp.json`, `.github/skills/`, `.github/hooks/`, `AGENTS.md` per project | + Squad adds `.squad/` (committed team state) | ✅ | Direct mapping | Phase 8 will produce the converter. | + +### B.10 Model selection + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| 30+ provider abstraction (`src/api/providers/`) — OpenAI, Anthropic, Bedrock, Azure, Ollama, OpenRouter | Restricted to GitHub-curated catalog (W-1 covers GPT/Claude/Gemini via Copilot subscription) — G-13 if vault uses non-Copilot models | `COPILOT_PROVIDER_BASE_URL` / `COPILOT_PROVIDER_TYPE` (openai/azure/anthropic) / `COPILOT_PROVIDER_API_KEY` (CW-2) — closes G-13 | same as CLI | **Chat 🟠 / CLI ✅** | CLI eliminates the BYOK gap | Resolves Q-030 for CLI; Chat-side stands. | +| Per-mode `apiConfigId` (different model per mode) | `.agent.md` `model:` (single name or prioritized array) | `.agent.md` `model:` | same as CLI | ✅ | — | 40 § Custom Chat Modes (1); 50 § 5.2. | +| Local model (Ollama, LM Studio) | None first-class — G-13 | OpenAI-compat endpoint via `COPILOT_PROVIDER_BASE_URL=http://localhost:11434/v1` | same as CLI | **Chat 🟠 / CLI ✅** | Confirmed in 50 § 7.2 | Big win for offline/cost-control workflows. | +| Default model selection (vault-wide) | Per `.agent.md` only (no global default outside Copilot's own catalog default) | `--model auto/` flag; `~/.copilot/settings.json` global | same as CLI | ✅ | Vault-level convention | 50 § 3.4. | + +### B.11 Sessions / state / history + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| Task history (per workspace globalState) | Multi-session list per workspace; "Sessions list" ribbon; **no portable export** — G-9 / Q-029 | `session-state//` is plain JSONL + Markdown plan + checkpoints (50 § 2.2) | + Squad commits team state to git (`.squad/log/`, per-agent `history.md`) | **Chat 🟠 / CLI ✅ / Squad ➕** | CLI is trivially backup-able | G-9 dropped from major to minor on CLI. | +| Checkpoints (shadow-git rollback per task) | Native `chat.checkpoints.enabled` + `Restore Checkpoint` + Fork (W-8) | `session-state//checkpoints/` per session | same as CLI | ✅ | Both paths match | 40 § Agent Mode (4); 50 § 2.2. | +| Fork conversation | `Fork Conversation` button (W-8) | Manual (`copilot --resume ` → branch) | same as CLI | ✅/🟡 | Chat is more ergonomic; CLI is scriptable | 40 § Agent Mode (4). | +| Export task history | None portable today — G-9 / Q-029 | `--share=PATH` Markdown transcript; full JSONL on disk | + Squad `squad sharing` export commands | **Chat 🟠 / CLI ✅ / Squad ➕** | Use `--share` or `xcopy session-state` | 50 § 12.2. | +| Full-text search across history | Limited (UI-driven) | SQLite FTS5 index in `session-store.db` (CW-4) | same as CLI | ➕ on CLI | — | 50 § 3.5. | + +### B.12 Approval / safety + +| Roo feature | Copilot Chat | Copilot CLI | Squad | Gap severity | Workaround | Notes | +|---|---|---|---|---|---|---| +| Per-tool confirmation prompt | Per-tool dialog with Allow/Always/Session/Workspace; `chat.permissions.default` (Default Approvals / Bypass / Autopilot) | Per-tool TTY prompt with `Kind(arg)` allow/deny grammar (CW-12) | same as CLI | ✅ | Map vault's "Always allow" lists per-tool | 40 § Agent Mode (5); 50 § 3.3. | +| Per-mode allowlist of pre-approved tools | `chat.tools.eligibleForAutoApproval` (org-managed) + per-tool dialog choices | `settings.json` `allowedTools` / `deniedTools`; `--allow-tool='…'` per-invocation; **deny wins** (CW-12) | same as CLI | ✅ (CLI ➕) | CLI's `Kind(arg)` is finer-grained than Chat | Both beat Roo. | +| `chat.tools.terminal.autoApprove` regex map (Chat) / `--allow-tool='shell(git:*)'` (CLI) | Regex-based command auto-approve (W-10 org-policy capable) | `Kind(arg)` allow/deny patterns; per-invocation flags | same as CLI | ✅/➕ | — | Material upgrade over Roo's per-server `alwaysAllow`. | +| Hooks (pre/post tool, session lifecycle) | None first-class (Preview `hooks:` in `.agent.md` frontmatter) | 13 events × `command`/`prompt` types (50 § 10.2); enables G-1 mitigation via `preToolUse` (CW-1) | + Squad's SDK `SessionHooks` for in-process hooks | **Chat 🔴 (no hooks → cannot mitigate G-1) / CLI 🟢 with caveats** | This is the load-bearing CLI advantage | CG-11 (sub-agent bypass), CG-13/14/15 are caveats. | +| Sandboxing | `chat.agent.sandbox.enabled` mac/linux only — G-14; ignored on Windows | Same — G-14 inherits | n/a | 🟡 | No regression vs Roo | Windows-platform limitation. | +| Org-managed policies | `chat.agent.networkFilter`, `chat.tools.global.autoApprove`, `chat.plugins.enabled`, etc. (W-10) | Six-key repo-settings allowlist (`disableAllHooks`, `hooks`, `enabledPlugins`, …) — CG-4 limits scope | + Squad's `protected-files` / `secret-handling` skills add prompt-level policy | **Chat ✅ / CLI 🟠 (CG-4 scope)** | Push policy to user-scope on CLI; Chat has richer enterprise controls | 50 § 10.5. | + +## C. Severity Tally + +Counts include the matrix rows in §§ B.1–B.12 (≈70 row-cells per path). Rows with dual severity contribute to both columns (Chat severity counted in Chat row, CLI severity counted in CLI row). Squad row counts only deltas where Squad is `+ ` or `same as CLI`. + +| Path | 🔴 | 🟠 | 🟡 | ✅ | ➕ | +|---|---|---|---|---|---| +| **Chat** | 2 | 8 | 12 | 22 | 4 | +| **CLI** | 0 | 7 | 11 | 27 | 8 | +| **Squad (delta over CLI)** | 0 | 0 | 0 | (rows where Squad is `same as CLI`) | 7 (parallel fan-out, Ralph daemon, casting registry, plugin marketplace, `secret-handling`/`protected-files` skills, `.squad/log/` portable state, in-process `SessionHooks`) | + +**Interpretation.** + +1. **Chat carries 2 blockers (G-1 file-regex on edit + B.8 row "headless invocation" being structurally absent for any CI/scripting workflow).** CLI eliminates **both** — the first via `preToolUse` (with CG-11 caveat), the second by being a CLI in the first place. +2. **CLI introduces no new blockers** but ships ~7 majors centered on observability/SDK churn/UI-loss (CG-1, CG-4, CG-7, CG-8, CG-11, plus inherited G-2, G-5). +3. **Wins favour the CLI by a meaningful margin** (8 ➕ vs 4 ➕). Chat's wins are unified-panel + multi-profile UX; CLI's wins are headless + hooks + BYOK + portability + skills + OTel + FTS5 + `Kind(arg)` permission grammar. +4. **Squad's value is real but narrow**: it adds 7 distinct capabilities on top of CLI (parallel orchestration, Ralph, casting, marketplace, two skills, portable state, in-process hooks), but is gated on accepting CG-12's alpha-stability tax. Only relevant on Path C. + +## D. Top 10 Most Important Rows + +The 10 highest-impact rows for path selection and playbook scoping (with one-line "what to do about it"): + +1. **B.2 row 2 — `groups[].fileRegex` (G-1).** `Chat 🔴 / CLI 🟠`. **Chat:** accept loss + prose enforcement. **CLI:** ship `preToolUse` PowerShell hook from 50 § 10.4; restrict `task` dispatch in regex-bound agents (CG-11). +2. **B.8 row 1 — Headless invocation.** `Chat n/a / CLI ✅`. CLI is the only path for CI/automation workflows; Path A users must accept "interactive only". +3. **B.10 row 1 — Provider abstraction / BYOK (G-13).** `Chat 🟠 / CLI ✅`. If the vault uses Ollama/Anthropic/Azure direct (Q-030), the CLI is required. +4. **B.4 row 6 — MCP secret model (CG-2 / Q-033).** `Chat ✅ (Credential Manager) / CLI 🟡 (env-var only)`. Pick one canonical secret store; vault must dual-author or generate. +5. **B.5 row 1 — Subagent dispatch.** `Chat ✅ / CLI ✅ / Squad ➕ parallel fan-out`. All three paths work; Squad adds parallel-by-default; Roo's serial enforcement is lost everywhere (G-4 minor). +6. **B.7 row 1 — Webview UI for mode CRUD (G-5 / CG-1).** `Chat 🟡 / CLI 🟠`. File-driven editing + Command Palette; Path D could re-add visual UI. +7. **B.8 row 2 — Structured event stream (CG-7 / Q-042).** `CLI 🟠`. Track [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52); meanwhile use `@github/copilot-sdk` streaming events. +8. **B.9 row 4 — Multi-profile vault automation (G-11).** `Chat 🟡 / CLI ✅`. CLI's `COPILOT_HOME` closes the gap; Chat needs a Phase-8 PowerShell helper for `…\profiles\\mcp.json`. +9. **B.11 row 4 — Chat history export (G-9).** `Chat 🟠 / CLI ✅`. CLI's plain JSONL is portable; Chat's profile-scoped DB is opaque (Q-029). +10. **B.12 row 4 — Hooks.** `Chat 🔴 (no hooks ↔ no G-1 mitigation) / CLI 🟢 (with CG-11 caveat)`. The single load-bearing reason to consider Path B over Path A. + +## E. Squad Column Interpretation + +The Squad column in the matrix is **not a third migration path**; it expresses **what Squad layers on top of CLI** (and only CLI — Squad has no `vscode.lm` dependency and cannot embed in Chat per [`30-squad-inventory.md` § Architecture](30-squad-inventory.md#architecture) and [`50-copilot-cli-research.md` § 6.2](50-copilot-cli-research.md#62-squad--vscodelm-resolves-q-010)). + +- `same as CLI` — Squad doesn't change behaviour for that row; Path C inherits the CLI cell. +- `+ ` — Squad **adds** a capability the bare CLI doesn't have (e.g., parallel fan-out, Ralph watch daemon, persistent named agents from a casting registry, `protected-files` / `secret-handling` skills, `.squad/log/` git-committed state, in-process `SessionHooks` via the SDK). +- `n/a` — Squad has no opinion on the surface (e.g., Windows path layout, MCP transport choice). + +**Squad is non-zero only on Path C.** Path A (Chat) and Path B (CLI built-ins) are unaffected by Squad's existence; Path D (vault-as-VSIX) cannot reuse Squad as-is. Phase 7 will weigh Squad's additive value (parallel orchestration, Ralph, casting registry) against its cost (CG-12 alpha-stability tax + Q-011 still open + the indirection-debugging tax noted in [`30-squad-inventory.md` § Preliminary Verdict](30-squad-inventory.md#preliminary-verdict-final-verdict-reserved-for-phase-7)). + +## F. Phase 7 / Phase 8 Hand-off + +### F.1 Rows that determine path selection (largest Chat-vs-CLI severity divergence) + +Phase 7's path-selection synthesis hinges on these rows where the dual severity diverges most: + +- **B.2 row 2 (G-1 `fileRegex`)** — Chat 🔴 vs CLI 🟠. **Decisive** if vault's `fileRegex` usage is broad (Q-047). If narrow → Chat survives; if broad → CLI required. +- **B.8 row 1 (headless invocation)** — Chat n/a vs CLI ✅. **Decisive** if any vault automation runs from CI / cron / pre-commit hooks today. +- **B.10 row 1 (BYOK, G-13)** — Chat 🟠 vs CLI ✅. **Decisive** iff Q-030 confirms vault uses non-Copilot models. +- **B.12 row 4 (hooks)** — Chat 🔴-for-G-1-mitigation vs CLI 🟢. **Decisive** because hooks are the only mechanism that closes G-1; if you need it, you need CLI. +- **B.9 row 4 (multi-profile, G-11)** — Chat 🟡 vs CLI ✅. **Tie-breaker**, not decisive on its own. + +### F.2 Rows that determine playbook complexity (Phase 8 effort sizing) + +These 🔴/🟠 rows have non-trivial workarounds that Phase 8 must script: + +- **B.2 row 2 / row 6 (G-1 + vault `fileRegex` examples)** — Phase 8 owns the `enforce-file-regex.ps1` reference + the per-agent regex policy table; must address Q-047, Q-037 (active-agent in payload), Q-039 (`pwsh` cold-start latency). +- **B.3 row 3 (G-2 per-mode rules folder)** — Phase 8 owns the inlining strategy (agent-body inline vs Markdown-link to `.instructions.md`). +- **B.4 row 3 (CG-3 schema fork)** — Phase 8 owns the `jq` migration + the canonical-source decision (which file is the truth; the other is generated). +- **B.4 row 6 (CG-2 secret model)** — Phase 8 owns the `[Environment]::SetEnvironmentVariable("KEY","val","User")` bootstrap and the dual-format converter for `${input:…}` ↔ `${KEY}`. +- **B.7 row 1 (G-5 / CG-1 webview UI)** — Phase 8 must decide whether to ship a thin Path-D VSIX for visual mode CRUD or accept file-driven editing. +- **B.8 row 2 (CG-7 structured output)** — Phase 8 must pick: `@github/copilot-sdk` for code-driven consumers, OTel for aggregate metrics, or accept text-only `copilot -p`. +- **B.9 row 4 (G-11 multi-profile)** — Phase 8 owns the PowerShell helper that enumerates `%APPDATA%\Code\User\profiles\*\` and re-points each profile's `mcp.json` (only relevant for Path A). +- **B.12 row 6 (CG-4 repo-settings allowlist)** — Phase 8 must encode the "wrap `copilot` in a project-local launcher that exports `--allow-tool` / `--deny-tool` / `--mode`" pattern, since per-project `allowedTools` is silently dropped. + +### F.3 Open questions still relevant to the matrix + +The matrix's severities depend on these still-open Q-IDs from [`99-open-questions.md`](99-open-questions.md): + +- **Q-047** (vault's actual `fileRegex` usage breadth) — directly determines whether G-1 stays 🟠 on CLI or re-escalates to 🔴 once you account for `task`-dispatched sub-agents (CG-11). **Phase 6 owns the count.** +- **Q-030** (does the vault use non-Copilot models?) — determines whether G-13 is 🟠 or moot on Chat. +- **Q-029** (chat-sessions JSON portability) — determines whether G-9 stays 🟠 on Chat. +- **Q-027 / Q-028** (Agent Plugins manifest + org policy) — determines Path-D viability scoring. +- **Q-046** (CLI binary bundling for Path-D VSIX) — determines whether Path D is "user installs CLI" vs "VSIX bundles CLI". +- **Q-031 / Q-033** — already resolved in Phase 5b-i; restated in B.4 rows 2 and 6 for traceability. + +### F.4 New questions opened during this synthesis + +- **Q-048** — Does Copilot CLI / Chat read `AGENTS.local.md` (gitignored personal layer) the way Roo does? CLI doc lists `Copilot.md` / `GEMINI.md` / `CODEX.md` / `CLAUDE.md` compat suffixes but `.local.md` suffix support is unverified. Affects B.3 row 5. Owner: Phase 8. +- **Q-049** — How is Roo's "always-on todo list re-injection" (every prompt turn re-emits the `update_todo_list` snapshot in `environment_details`) replicated under Copilot? No first-class equivalent in Chat or CLI; can be approximated by an `agentStop` hook (CLI) or a `.prompt.md` rerun (Chat) but neither is the same UX. Affects B.6 row 5. Owner: Phase 8. + +## Cross-links + +- [`10-roo-inventory.md`](10-roo-inventory.md) · [`20-roo-vault-inventory.md`](20-roo-vault-inventory.md) · [`30-squad-inventory.md`](30-squad-inventory.md) · [`40-copilot-chat-research.md`](40-copilot-chat-research.md) · [`50-copilot-cli-research.md`](50-copilot-cli-research.md) · [`70-migration-paths.md`](70-migration-paths.md) · [`90-decision-log.md`](90-decision-log.md) · [`99-open-questions.md`](99-open-questions.md) diff --git a/docs/investigation/roo-to-copilot/70-migration-paths.md b/docs/investigation/roo-to-copilot/70-migration-paths.md new file mode 100644 index 00000000000..4ab04758318 --- /dev/null +++ b/docs/investigation/roo-to-copilot/70-migration-paths.md @@ -0,0 +1,504 @@ +--- +phase: 7 +status: complete +owner: architect-recommendation-subtask +last_updated: 2026-04-26 +sources: + - docs/investigation/roo-to-copilot/10-roo-inventory.md + - docs/investigation/roo-to-copilot/20-roo-vault-inventory.md + - docs/investigation/roo-to-copilot/30-squad-inventory.md + - docs/investigation/roo-to-copilot/40-copilot-chat-research.md + - docs/investigation/roo-to-copilot/50-copilot-cli-research.md + - docs/investigation/roo-to-copilot/60-gap-analysis.md + - docs/investigation/roo-to-copilot/99-open-questions.md +--- + +# Phase 7 — Migration Path Options + +> Parent plan: [`00-plan.md`](00-plan.md) · Index: [`README.md`](README.md) · Gap matrix: [`60-gap-analysis.md`](60-gap-analysis.md) + +**What this file is for.** Score the four candidate migration paths (A/B/C/D) plus a Hybrid against a weighted decision-criteria framework derived from the user's actual context (Windows 11 + [`roo-vault`](../../../../roo-vault) with 17 modes / 7 MCP servers / multi-project symlink layout) and the unified Gap Catalog from Phase 6, then deliver an opinionated recommendation that hands off to [`80-migration-playbook.md`](80-migration-playbook.md). + +**Path definitions** (used verbatim by downstream phases): + +- **Path A — Copilot Chat only.** `.github/agents/*.agent.md` + `.github/copilot-instructions.md` + `.github/instructions/*.instructions.md` + `.vscode/mcp.json` + user-scope `*.toolsets.jsonc`. No CLI, no Squad, no VSIX. +- **Path B — Copilot CLI only.** `~/.copilot/agents/*.agent.md` + `~/.copilot/instructions/` + `~/.copilot/mcp-config.json` + hooks for `fileRegex` policy. CLI is the primary surface; Chat optional but unmanaged. +- **Path C — CLI + Squad overlay.** Path B plus Squad's parallel orchestration (`fleet-dispatch`, `wave-dispatch`, named-agent registry, Ralph daemon). Inherits Squad alpha-maturity risk (CG-12). +- **Path D — Vault-as-VSIX.** Custom VS Code extension shipping the vault via `@github/copilot-sdk` (Path-D embeddability = 🟡 per [50 § 7](50-copilot-cli-research.md#7-sdk-githubcopilot-sdk--full-export-catalogue-phase-5b-ii-b-1)) or via `vscode.chat.createChatParticipant` + Language Model Tools API. Maximum control; ~1 engineer-month + ongoing 0.x churn. +- **Path Hybrid — Chat (interactive) + CLI (automation).** Both surfaces, sharing `.agent.md` and `AGENTS.md` files; MCP duplicated per the [CG-3 schema fork](50-copilot-cli-research.md#13-limits--known-gaps-relative-to-roo-cli-gap-catalog--phase-5b-ii-b-2). + +--- + +## § 1 — Decision-Criteria Framework + +Eight weighted criteria, each scored 1 (worst) – 5 (best) per path. Weights sum to 100%. + +| # | Criterion | Weight | What it measures | Rationale | +|---|---|---:|---|---| +| **C1** | **Capability fidelity to Roo** | 30% | How many Phase-6 rows stay 🔴/🟠 after migration; how cleanly the vault's 17 modes survive | Highest weight because the user's verbatim goal in [`00-plan.md`](00-plan.md) is *"replicate the Roo-Code experience — modes, orchestrator, MCP, custom prompts, rules, memory"*. Anything that drops below ~80% fidelity contradicts the brief. | +| **C2** | **Effort to migrate** | 20% | Engineer-days for first project + steady-state per new project | Single-developer migration ([`00-plan.md` § Non-goals](00-plan.md)); time spent here doesn't ship features. The vault's 17 modes scale this linearly. | +| **C3** | **Operational risk** | 15% | Alpha/preview surface area, upstream-fix dependencies, breaking-change cadence | The user is the only operator. A 0.x dep that breaks weekly is materially worse than a stable surface with a known gap. Squad v0.9.1 (CG-12) and `@github/copilot-sdk` 0.3.0 (CG-8, 54 versions in 5 months) are the canonical examples. | +| **C4** | **Day-to-day UX** | 10% | One panel vs two; GUI vs slash commands; mode picker, MCP toggles, diff view | The vault user is an IDE-centric developer (VS Code Stable per [`00-plan.md` § Constraints](00-plan.md)). Pure-CLI workflows materially change the muscle memory; mixed-surface workflows split attention. | +| **C5** | **Automation / CI fitness** | 10% | Headless invocation, JSON event stream, OTel, exit codes | The user has automation today (Ralph-style watch loops are documented in the vault; [`apps/cli/src/agent/json-event-emitter.ts`](../../../apps/cli/src/agent/json-event-emitter.ts) in Roo proves they consume NDJSON). Any path that loses headless capability cannot run pre-commit / CI / cron workflows. | +| **C6** | **Vault portability** | 5% | Multi-machine, multi-profile, symlink-friendly | Lower weight because the user has one active dev box ([`00-plan.md` § Constraints](00-plan.md): single Windows 11 machine), but the vault is *designed* for multi-machine (`setup-vault.ps1`, [`20 § Notable patterns`](20-roo-vault-inventory.md)). Future-proofing matters. | +| **C7** | **Lock-in / reversibility** | 5% | Can the user back out and re-adopt Roo or pivot to another agent? Are config files cross-tool-readable? | `.agent.md` + `AGENTS.md` are cross-tool standards (Claude Code, Codex, Cursor, Gemini CLI all read at least one). A path that converges on those is reversible; a path that ships a bespoke VSIX is not. | +| **C8** | **Cost** | 5% | Copilot subscription tier, GitHub Actions minutes for cloud agent, model BYOK savings | Low weight because the user already has Copilot ([`00-plan.md` § Constraints](00-plan.md): *"No paid tier assumptions beyond the user's existing subscription"*), but BYOK to local Ollama (CW-2) is a strict cost win for CLI-bearing paths. | + +**Scoring conventions.** +- **C1 fidelity** maps roughly: 5 = ≤1 🟠 surviving, no 🔴; 4 = 2-3 🟠 / 0 🔴; 3 = 4-6 🟠 OR 1 🔴; 2 = 7+ 🟠 OR 2 🔴; 1 = ≥3 🔴. +- **C2 effort** is *inverse* (lower effort → higher score): 5 = 1–3 days first-project + trivial steady-state; 4 = 3–7 days; 3 = 1–2 weeks; 2 = 2–4 weeks; 1 = 1+ engineer-month. +- **C3 risk** is *inverse* (lower risk → higher score): 5 = stable GA APIs only; 1 = alpha + multiple upstream-blocked bugs. + +--- + +## § 2 — Path-by-Path Scoring + +### § 2.A — Path A: Copilot Chat only + +**1. Summary.** Disable the Roo-Code extension. Convert each of the vault's 17 modes to `.github/agents/.agent.md` (project-scope) and `%APPDATA%\Code\User\prompts\*.agent.md` (user-scope). Move `~/.roo/rules/` → `%APPDATA%\Code\User\prompts\*.instructions.md`. Move `mcp_settings.json` → `%APPDATA%\Code\User\mcp.json` (rename `mcpServers` → `servers`, add `${input:…}` placeholders). Per-project: `.roo/mcp.json` → `.vscode/mcp.json`; `.roomodes` → `.github/agents/`. Keep working in the VS Code Chat panel only. **No CLI, no Squad, no custom extension.** + +**2. What you keep from the vault.** +- ✅ All 17 mode definitions (slug/name/roleDefinition/customInstructions/description) port mechanically per the [60 § B.1](60-gap-analysis.md#b1-modes--agents-schema) row mappings. +- ✅ Layered composition (built-in → user → project) survives intact ([60 § B.1 row 7](60-gap-analysis.md#b1-modes--agents-schema)). +- ✅ All 7 MCP servers (`mcpServers` → `servers` rename, then `${input:…}` for secrets) — Chat's Credential Manager UX is *better* than Roo's gitignored-JSON pattern ([60 § B.4 row 6](60-gap-analysis.md#b4-mcp-integration)). +- ✅ `AGENTS.md` reads natively (W-5). +- ✅ `~/.roo/rules/` → `%APPDATA%\Code\User\prompts\*.instructions.md` via symlink (vault `setup-vault.ps1` retargets cleanly). +- ⚠️ `.roomodes` `groups` array → `.agent.md` `tools:` (mechanical group→tool expansion, finer-grained — strict win for the *tool* axis only). + +**3. What you lose** (Phase-6 rows that survive as 🔴/🟠 on Chat): +- 🔴 **G-1 `groups[].fileRegex` per-mode edit restriction** ([60 § B.2 row 2](60-gap-analysis.md#b2-tool-restrictions-per-mode-toolmcpfile-gating)). Chat has **no hook surface**; the only enforcement is prose in `.agent.md` ("only edit `.md` files"). Affects ≥3 vault modes (architect, translate, docs-extractor — confirmed in [20 § Global Settings](20-roo-vault-inventory.md)). Per Q-047 this row alone is binding. +- 🔴 **G-2 per-mode `.roo/rules-/` folder** ([60 § B.3 row 3](60-gap-analysis.md#b3-custom-prompts--rules)). No `applyTo: agent:` glob exists; rules are file-glob-scoped, not agent-scoped. Workaround: inline rule bodies into each `.agent.md`, accepting duplication. +- 🟠 **G-13 BYOK / local-model providers** ([60 § B.10 row 1](60-gap-analysis.md#b10-model-selection)) — *only matters if vault uses Ollama/Anthropic-direct/Azure-OpenAI*; Q-030 unresolved for the user but the vault `setup_dev_box.ps1` does install LiteLLM/Qdrant infrastructure suggestive of local-model intent. +- 🟠 **G-9 chat-history portability** ([60 § B.11 row 1](60-gap-analysis.md#b11-sessions--state--history)) — sessions live in profile-scoped state DB; no portable JSON export (Q-029). +- 🟠 **B.8 row 1 — headless invocation is structurally absent.** Any pre-commit / CI / cron workflow the user has *or might want* requires shelling out to a separate tool. This is not a "gap" per se; it's a categorical limitation of choosing a GUI as the only surface. +- 🟠 **G-5 / CG-1-equivalent — workspace-scoped `*.toolsets.jsonc`** is still on Backlog ([microsoft/vscode#251515](https://github.com/microsoft/vscode/issues/251515)); user-scope tool sets only. +- 🟡 **Q-049 — `update_todo_list` re-injection** has no Chat equivalent (no `userPromptSubmitted` hook). + +**4. What you gain** (corresponding Wins): +- ➕ **W-4 first-class secret hygiene** via `${input:id}` + Windows Credential Manager — strictly better than the vault's "gitignored `mcp_settings.json` with live tokens" pattern. +- ➕ **W-2 Agent Plugins (Preview) marketplace** for community modes. +- ➕ **W-7 parallel sub-agent dispatch** (Roo's serial enforcement was a *limitation*, not a feature). +- ➕ **W-8 native checkpoints + Fork Conversation** — strictly better than Roo's per-task git-shadow rollback. +- ➕ **W-12 unified panel UX** — single chat surface for all agents; no extension overhead. +- ➕ **W-10 org-policy ceiling** — `chat.tools.terminal.autoApprove` regex map, `chat.permissions.default`, etc. + +**5. Effort estimate.** +- **First project:** **3–7 days.** Mechanical conversion of 17 modes + 7 MCP servers + rule files + `setup-vault.ps1` retargeting + per-agent prose enforcement of `fileRegex` rules. +- **Steady-state per new project:** **<1 day** — copy `.github/agents/`, `.github/instructions/`, `.vscode/mcp.json` template; commit `AGENTS.md`. +- **Ongoing maintenance:** **~1 hour/month** — mostly tracking VS Code Insider/Stable changes to the agents/instructions schema (expect monthly small diffs while the surface is in Preview). + +**6. Risks** (severity · ID · upstream link). +- 🔴 **G-1 unmitigated.** Cited multiple times above. No on-disk control; relies on the model honouring the prose. **Binding constraint.** +- 🟠 **G-2 inlining bloat.** Each agent body grows by the size of its rules folder; risk of hitting the documented "no longer than 2 pages" guidance for instructions (Q-017). +- 🟠 **Q-024 — `*.toolsets.jsonc` not synced** by Settings Sync; multi-machine vault loses tool-set definitions silently. +- 🟡 **G-11 multi-profile.** Phase 8 must script profile-aware `mcp.json` symlinks (Q-026). +- 🟡 **G-9 lock-in.** Chat sessions are not portable; if the user pivots later, history is lost. + +**7. Prerequisites.** +- GitHub Copilot subscription (any tier — even Free works for Chat per [40 § Storage](40-copilot-chat-research.md)). +- VS Code Stable, recent enough that `.agent.md` (post-rename) is supported (Q-016 — exact version unverified; Insider 1.96+ confirmed in Phase 4d). +- Node 20+ if any MCP server is `npx`-launched. +- Windows Credential Manager (default on Windows 11). + +**8. Open questions specific to Path A.** +- **Q-005** (lossy converter fields), **Q-015** (profile-scoped agents discovery), **Q-017** (instructions size cap), **Q-024** (`*.toolsets.jsonc` Settings Sync), **Q-026** (profile-id `mcp.json` symlink helper), **Q-027** (Agent Plugins outside Preview channel — only relevant if shipping community modes), **Q-029** (sessions JSON export), **Q-047** (vault's `fileRegex` blast radius), **Q-049** (todo re-injection). + +**9. Score table.** + +| Criterion | Weight | Score (1–5) | Weighted | +|---|---:|---:|---:| +| C1 Capability fidelity | 30% | **2** (2 🔴 + ~6 🟠 surviving) | 0.60 | +| C2 Effort | 20% | **4** (3–7 days first project; trivial steady-state) | 0.80 | +| C3 Operational risk | 15% | **4** (Chat is GA in Stable; preview surfaces well-isolated) | 0.60 | +| C4 Day-to-day UX | 10% | **5** (single panel, zero context switch) | 0.50 | +| C5 Automation / CI | 10% | **1** (no headless mode at all) | 0.10 | +| C6 Vault portability | 5% | **3** (profile-scoped `mcp.json` needs PowerShell helper) | 0.15 | +| C7 Lock-in / reversibility | 5% | **4** (`.agent.md` + `AGENTS.md` are cross-tool) | 0.20 | +| C8 Cost | 5% | **3** (no BYOK; locked to GitHub-curated catalog) | 0.15 | +| **Total** | **100%** | — | **3.10** | + +**10. Verdict.** Choose Path A only if (a) you do not depend on `fileRegex` for safety, (b) you never run agents from CI / pre-commit / cron, and (c) you primarily use the IDE for interactive coding. **Not recommended for the user's current vault** — G-1 alone disqualifies it for the architect/translate/docs-extractor modes. + +--- + +### § 2.B — Path B: Copilot CLI only + +**1. Summary.** Install `@github/copilot` (npm). Set `COPILOT_HOME=/global-settings/copilot` so the entire CLI config tree is vault-anchored. Convert vault modes to `~/.copilot/agents/*.agent.md` (same body schema as Path A — files port directly). Move rules to `~/.copilot/instructions/`. Move MCP to `~/.copilot/mcp-config.json` (top-level `mcpServers`, env-var substitution). Ship a `preToolUse` PowerShell hook (per [50 § 10.4](50-copilot-cli-research.md#104-pretooluse-deep-dive--the-fileregex-substitute)) implementing the `fileRegex` policy. Drive everything from a terminal. VS Code becomes a plain editor. + +**2. What you keep.** +- ✅ All 17 modes — `.agent.md` body is identical to Path A; only the storage path changes. +- ✅ All rules — `~/.roo/rules/` → `~/.copilot/instructions/`; symlink retargets cleanly. +- ✅ All 7 MCP servers — `mcpServers` schema is preserved (no rename), env-var substitution honoured. +- ✅ `AGENTS.md` (CLI reads it natively per [50 § 4.1](50-copilot-cli-research.md)). +- ✅ Built-in starter agents (`code-review`, `general-purpose`, `explore`, `research`, `rubber-duck`, `task`, `configure-copilot`) — overridable by user files (CLI better-than-Roo: 7 starting points vs Roo's 5 built-ins). + +**3. What you lose.** +- 🟠 **CG-1 webview UI loss** — `ModesView.tsx`, `McpServerRestriction.tsx`, `DeleteModeDialog.tsx`, mode-picker GUI, MCP toggle UI, diff preview. **The single biggest UX regression.** Mitigation: Command Palette `Chat: New Agent…` or hand-edit `.agent.md`. +- 🟠 **CG-7 no structured event stream** ([copilot-cli#52](https://github.com/github/copilot-cli/issues/52)) — Roo's NDJSON ([`apps/cli/src/agent/json-event-emitter.ts`](../../../apps/cli/src/agent/json-event-emitter.ts), 28+ event types) has no equivalent; plain text only. **Drop down to `@github/copilot-sdk` for code-driven consumers.** +- 🟠 **CG-11 sub-agent hook bypass** ([copilot-cli#2392](https://github.com/github/copilot-cli/issues/2392)) — `task`-dispatched sub-agents bypass `preToolUse`. **Demotes G-1 mitigation from "complete" to "complete for boot-agent only".** Requires restructuring orchestrator flows to use `--agent` boot mode instead of `task` dispatch for any regex-bound mode. +- 🟠 **CG-8 SDK 0.x churn** — only matters if user writes SDK consumers; CLI itself is more stable. +- 🟠 **CG-4 repo-settings 6-key allowlist** — per-project `allowedTools`/`deniedTools` silently dropped; needs a launcher wrapper. +- 🟠 **G-2 inherited** (per-mode rules folder still has no first-class equivalent). +- 🟡 **CG-2 secret model** (env-var only, no Credential Manager prompt) — vault must persist via `[Environment]::SetEnvironmentVariable("KEY","val","User")`. +- 🟡 **CG-3 MCP schema fork** — only matters if also using Chat (i.e., not on pure Path B). +- 🟡 **Q-049 todo re-injection** — approximated via `agentStop` or `userPromptSubmitted` hook; not a clean port. + +**4. What you gain.** +- ➕ **CW-1 G-1 mitigation via `preToolUse` hook** — the headline CLI win. Reference impl in [50 § 10.4](50-copilot-cli-research.md#104-pretooluse-deep-dive--the-fileregex-substitute). +- ➕ **CW-2 BYOK** — `COPILOT_PROVIDER_BASE_URL` / `COPILOT_PROVIDER_TYPE` (openai/azure/anthropic) closes G-13 entirely. Ollama works. +- ➕ **CW-3 OpenTelemetry** export via standard OTLP env vars. +- ➕ **CW-4 SQLite FTS5** session search. +- ➕ **CW-6 single-env-var portability** (`COPILOT_HOME`) — closes G-11 entirely; massively simpler than Chat's per-profile-id symlinks. +- ➕ **CW-7 headless invocation** (`copilot -p "…" -s --no-ask-user --allow-tool=…`) — unlocks pre-commit / cron / CI workflows. +- ➕ **CW-12 `Kind(arg)` permission grammar** — `shell(git:*)` / `write(./src/**)` / `url(github.com)`; finer than Roo's per-server `alwaysAllow`. +- ➕ **Skills (Agent Skills standard)** — cross-tool with Claude Code, Cursor, Gemini CLI, Codex. +- ➕ **`/mcp` REPL family** — keyboard-driven MCP ops far better than Chat's UI toggles. + +**5. Effort estimate.** +- **First project:** **1–2 weeks.** Mechanical mode conversion (~3 days) + `preToolUse` hook authoring + per-agent test (~2 days) + Windows-Bash-vs-PowerShell skill dual-shipping (~1 day) + muscle-memory retraining (~3 days). +- **Steady-state per new project:** **<1 day** — `.github/agents/` + `.github/mcp.json` + `.github/hooks/` per project; or rely on `COPILOT_HOME` user-scope. +- **Ongoing maintenance:** **~2–4 hours/month** — CLI ships weekly (54 versions in 5 months for the SDK; CLI itself similar cadence); track upstream issues #2392 / #52 / #2540 / #2013. + +**6. Risks.** +- 🟠 **CG-11 `#2392` unfixed.** Until upstream ships, sub-agent dispatched modes leak past `preToolUse`. Hard cap on the G-1 mitigation. +- 🟠 **Q-039 — `pwsh` cold-start latency** on user's Windows 11 box. 150–400 ms typical, >1 s with module loads. Per-tool overhead on hook-heavy policies. +- 🟠 **CG-1 ergonomic shock.** Users coming from a webview UI will feel the loss day-1. +- 🟡 **Q-037 — active-agent name not in hook payload.** Workaround is sidecar state file from `subagentStart`. +- 🟡 **CG-13 / CG-14 / CG-15** — assorted hook bugs ([#2893](https://github.com/github/copilot-cli/issues/2893) parallel-call race, [#2540](https://github.com/github/copilot-cli/issues/2540) plugin hooks, [#2013](https://github.com/github/copilot-cli/issues/2013) `modifiedArgs` ignored). + +**7. Prerequisites.** +- GitHub Copilot subscription (any tier). +- Node 20+ (CLI runtime). +- Windows 11 with PowerShell 7+ (`pwsh.exe`) for hook reference impl; built-in `powershell.exe` 5.1 works but is slower per Q-039. +- Optionally: Ollama / LM Studio if pursuing the BYOK win. +- A terminal-friendly mindset. + +**8. Open questions specific to Path B.** +- **Q-035** (`preToolUse` Windows reference — partially resolved), **Q-036** (user-scope hook discovery), **Q-037** (active-agent in payload), **Q-038** (`http` hooks on CLI), **Q-039** (pwsh cold-start), **Q-040** (`${env:VAR}` in hook env), **Q-041** (`user-invocable` skill frontmatter), **Q-042** ([copilot-cli#52](https://github.com/github/copilot-cli/issues/52) tracking), **Q-043** (granular exit codes), **Q-047** (vault `fileRegex` × sub-agent intersection). + +**9. Score table.** + +| Criterion | Weight | Score (1–5) | Weighted | +|---|---:|---:|---:| +| C1 Capability fidelity | 30% | **4** (0 🔴, ~7 🟠 with G-1 mitigated; CG-11 caveat) | 1.20 | +| C2 Effort | 20% | **3** (1–2 weeks; hook authoring tax; skill dual-shipping) | 0.60 | +| C3 Operational risk | 15% | **3** (4 active CLI bugs bound the headline win; weekly releases) | 0.45 | +| C4 Day-to-day UX | 10% | **2** (CLI-only; no GUI; muscle-memory shift) | 0.20 | +| C5 Automation / CI | 10% | **5** (purpose-built; OTel; FTS5; share/resume) | 0.50 | +| C6 Vault portability | 5% | **5** (single env var `COPILOT_HOME` closes G-11) | 0.25 | +| C7 Lock-in / reversibility | 5% | **5** (`.agent.md` + `AGENTS.md` cross-tool; SDK MIT) | 0.25 | +| C8 Cost | 5% | **5** (BYOK to Ollama possible) | 0.25 | +| **Total** | **100%** | — | **3.70** | + +**10. Verdict.** Choose Path B if you live in the terminal already, want to script your agent workflows, and accept the loss of the visual mode CRUD. **Strong choice for headless-heavy users; compromised choice for IDE-centric users like the vault owner.** + +--- + +### § 2.C — Path C: CLI + Squad overlay + +**1. Summary.** Path B + install `@bradygaster/squad-cli` (alpha v0.9.1) and adopt Squad's parallel-orchestration patterns: `squad fan-out`, `squad wave-dispatch`, `squad fleet-dispatch`, the named-agent casting registry, and the Ralph watch daemon. Squad sits *in front of* the CLI: invocations become `squad …` rather than `copilot …`. The CLI's `.agent.md` files survive untouched; Squad reads them. + +**2. What you keep.** +- ✅ Everything Path B keeps. +- ✅ Plus Squad-specific affordances: persistent named agents (e.g., `squad cast architect-1 architect-2`), parallel `task` fan-out at concurrency caps, `.squad/log/` git-committed state, in-process `SessionHooks` via the SDK adapter. + +**3. What you lose.** +- All Path-B losses, plus: +- 🟠 **CG-12 Squad alpha-stability tax.** v0.9.1; no SemVer commitment; runtime ESM patcher needed for SDK 0.1.32 (per [Phase 5b-ii-B-1 finding](90-decision-log.md#2026-04-26-1758--phase-5b-ii-b-1-githubcopilot-sdk-exports-catalogued-path-d-embeddability--with-shim)); pinned ~3 minor versions behind current SDK; doctor command exists *because* upstream churn breaks it. **Q-011 still open** on Windows support state and breaking-change cadence. +- 🟠 **Indirection-debugging tax** — when something goes wrong, the failure can be in: the model, the CLI, the SDK adapter, Squad's orchestration layer, the casting registry, or the shipped skill. Triage surface is 2× Path B. +- 🟠 **Squad uses non-canonical config locations** (`.copilot/mcp-config.json` instead of `.github/mcp.json` per Q-031). Vault must dual-author or pick one canonical source. +- 🟠 **Ralph default invokes the wrong CLI** (`gh copilot` legacy extension, not `@github/copilot`) — vault adoption requires `--agent-cmd "copilot"` override. Easy to forget. + +**4. What you gain.** +- ➕ **Parallel orchestration** is the headline. If your workflow benefits from N-way fan-out (e.g., "review this PR with architect + security + tester in parallel and merge results"), Squad is purpose-built; CLI's bare `task` tool is sequential-by-prose. +- ➕ **Casting registry** — persistent named agents with their own per-agent histories in `.squad/agents//`. Roo has no equivalent. +- ➕ **Ralph watch daemon** — file-watch-triggered agent invocation; replicates Roo's autonomous loops. +- ➕ **23 ready-made skills** in `c:/git/squad/.copilot/skills/` (some directly applicable: `secret-handling`, `protected-files`, `model-selection`). + +**5. Effort estimate.** +- **First project:** **2–4 weeks.** Path-B effort (1–2 weeks) + Squad onboarding (3–5 days) + casting/fan-out workflow design (3–5 days) + alpha-bug triage (variable). +- **Steady-state per new project:** **1–3 days** — heavier than Path B because each project may want a `.squad/` state subtree. +- **Ongoing maintenance:** **~6–10 hours/month** — alpha-software tax; Squad's SDK pin lags upstream so doctor commands and runtime patches need re-running on each `npm update`. + +**6. Risks.** +- 🟠 **CG-12 alpha maturity.** Single largest concern. Q-011 (Windows support, breaking-change cadence) unresolved. +- 🟠 **Two-stack debugging surface.** +- 🟠 **Squad cannot embed in VS Code** ([resolved Q-010](99-open-questions.md)) — Squad has zero `vscode.lm` deps, so any future Path-D pivot abandons Squad. +- 🟡 **Skills cross-tool surface fragments** — Squad's skills are Bash-first; Windows requires dual-shipping. + +**7. Prerequisites.** +- All Path-B prereqs. +- Tolerance for v0.x alpha software in a daily driver. +- A workflow that genuinely needs parallel orchestration (otherwise Squad's value prop collapses to "an extra abstraction layer"). + +**8. Open questions specific to Path C.** +- **Q-011** (Squad alpha stability commitment), **Q-031** (`.copilot/mcp-config.json` non-canonical — already resolved as "non-canonical, use `.github/mcp.json`"), **Q-034** (sub-agent depth/concurrency caps under nested orchestrators), all Path-B Qs. + +**9. Score table.** + +| Criterion | Weight | Score (1–5) | Weighted | +|---|---:|---:|---:| +| C1 Capability fidelity | 30% | **4** (same as B; parallel-fan-out adds beyond Roo) | 1.20 | +| C2 Effort | 20% | **2** (2–4 weeks) | 0.40 | +| C3 Operational risk | 15% | **2** (alpha + double stack + indirection) | 0.30 | +| C4 Day-to-day UX | 10% | **2** (CLI-only, plus a second CLI on top) | 0.20 | +| C5 Automation / CI | 10% | **5** (parallel + Ralph + portable state) | 0.50 | +| C6 Vault portability | 5% | **4** (inherits CLI's `COPILOT_HOME`; Squad adds non-canonical paths) | 0.20 | +| C7 Lock-in / reversibility | 5% | **3** (Squad-specific concepts don't port back) | 0.15 | +| C8 Cost | 5% | **5** (inherits CLI BYOK) | 0.25 | +| **Total** | **100%** | — | **3.20** | + +**10. Verdict.** Choose Path C only if you have a **demonstrated parallel-orchestration workload** (e.g., multi-agent code review, A/B model consensus) and tolerate alpha software. **Not recommended for the vault's current 17-mode/sequential-orchestrator pattern** — the marginal value over Path B is small and the maintenance cost is high. + +--- + +### § 2.D — Path D: Vault-as-VSIX + +**1. Summary.** Build a custom VS Code extension that ships the vault's modes/rules/MCP and consumes either `@github/copilot-sdk` (extension-host process — embeddability = 🟡 per [50 § 7](50-copilot-cli-research.md#7-sdk-githubcopilot-sdk--full-export-catalogue-phase-5b-ii-b-1)) or registers via the chat extension API (`vscode.chat.createChatParticipant` + Language Model Tools API + `contributes.languageModelTools`). Re-create Roo's `ModesView.tsx` / `McpServerRestriction.tsx` UX as either chat-participant UI or a webview ↔ extension-host postMessage bridge. **Maximum control; closes G-1 and G-2 cleanly because you're writing the enforcement code.** + +**2. What you keep.** +- ✅ Everything from Roo, structurally — because you re-implement what you need on top of Copilot's stable surfaces. +- ✅ `fileRegex` enforcement (your own VSIX checks before forwarding the tool call). +- ✅ Per-mode rules folder (your own VSIX loads the right files per active agent). +- ✅ Visual mode CRUD (your own webview). + +**3. What you lose.** +- 🔴 **~1 engineer-month** of *unproductive* work (per [50 § 7](50-copilot-cli-research.md#7-sdk-githubcopilot-sdk--full-export-catalogue-phase-5b-ii-b-1) verdict). The user is a single developer; this is a non-trivial slice of capacity. +- 🟠 **Ongoing 0.x SDK churn maintenance.** SDK at 0.3.0, 54 versions in 5 months, breaking changes per minor. You become the Squad team for your own vault. +- 🟠 **CLI-bundling decision (Q-046).** Either user installs `@github/copilot` separately (degrades first-run UX) or VSIX bundles it (size + signing + auto-update conflicts). +- 🟠 **Q-027 — Agent Plugins channel is Preview.** The stable alternative (`vscode.chat.createChatParticipant` + Language Model Tools API) is more code. +- 🟡 **Q-044, Q-045** — SDK `acpServer` export presence and programmatic MCP-server registration not yet confirmed. +- 🟡 Inherits Path-B's CG-7 (no structured events from CLI; you'd need to write your own bridge using SDK streaming events). + +**4. What you gain.** +- ➕ **G-1 and G-2 closed cleanly.** No upstream-fix dependency; you control the enforcement. +- ➕ **Visual mode CRUD restored.** Replicate Roo's UX exactly. +- ➕ **Per-mode rules folder restored** (your VSIX loads `.roo/rules-/` directly). +- ➕ **Future-proofing.** The VSIX is a stable abstraction layer between the vault and Copilot's evolving surfaces. When Copilot ships `fileRegex` natively, you remove your shim; when they break the schema, you absorb it. +- ➕ **Optional cloud-agent reuse** (`@github/copilot-sdk` exposes session APIs). + +**5. Effort estimate.** +- **First project:** **3–6 weeks** (the brief's "~1 engineer-month" target). Includes: VSIX scaffold + extension-host SDK harness + chat-participant registration + tool-allowlist enforcement + webview re-implementation of mode CRUD + first-run CLI-detect-or-bundle UX + initial `fileRegex` enforcement + skills/instructions ingestion. +- **Steady-state per new project:** **<1 day** — the VSIX reads vault config from `roo-vault/projects//`. +- **Ongoing maintenance:** **~10–20 hours/month** — SDK churn + Marketplace version cycles + your own bug surface. + +**6. Risks.** +- 🔴 **Sunk-cost risk.** Spend 4–6 weeks; Copilot ships `fileRegex` natively a month later; the VSIX becomes redundant. +- 🟠 **CG-8 SDK 0.x churn.** +- 🟠 **Marketplace gating** for personal use — Q-027 / Q-028 unresolved on whether you can ship this VSIX outside the Agent Plugins Preview channel. +- 🟠 **Q-046 — VSIX size** if bundling CLI binary (tens of MB). +- 🟡 **Single-developer maintenance burden** — if the user takes a month off, the VSIX rots. + +**7. Prerequisites.** +- All Path-B prereqs. +- Solid VS Code extension-development experience (Yeoman generator, `npm i vscode`, debugging in the Extension Development Host). +- Willingness to commit ~1 month of focused engineering before seeing usable output. +- Optionally a publisher account on the VS Code Marketplace. + +**8. Open questions specific to Path D.** +- **Q-027** (extension manifest path outside Agent Plugins Preview), **Q-028** (org-management for plugins), **Q-044** (`acpServer` export), **Q-045** (programmatic MCP registration), **Q-046** (CLI bundling). + +**9. Score table.** + +| Criterion | Weight | Score (1–5) | Weighted | +|---|---:|---:|---:| +| C1 Capability fidelity | 30% | **5** (you control enforcement; G-1/G-2 closed) | 1.50 | +| C2 Effort | 20% | **1** (3–6 weeks first project) | 0.20 | +| C3 Operational risk | 15% | **2** (SDK 0.x + sunk-cost + Marketplace gating) | 0.30 | +| C4 Day-to-day UX | 10% | **5** (rebuild Roo's UX exactly) | 0.50 | +| C5 Automation / CI | 10% | **3** (extension-host doesn't help CI; CLI still needed) | 0.30 | +| C6 Vault portability | 5% | **4** (VSIX installs anywhere; vault config decoupled) | 0.20 | +| C7 Lock-in / reversibility | 5% | **2** (you now own a codebase) | 0.10 | +| C8 Cost | 5% | **3** (no BYOK natively; engineering time is real cost) | 0.15 | +| **Total** | **100%** | — | **3.25** | + +**10. Verdict.** Choose Path D only if (a) you have a month of focused capacity, (b) the vault's `fileRegex` enforcement is genuinely safety-critical (e.g., production secrets, regulatory edits), and (c) you're prepared to maintain a personal extension long-term. **Not recommended as a Phase-1 migration step** — but viable as a Phase-3 escalation if Path A/B/Hybrid hit unacceptable gaps. + +--- + +### § 2.E — Path Hybrid: Chat (interactive) + CLI (automation) + +**1. Summary.** Use Path A's Chat surface for interactive coding (the IDE you already live in) and Path B's CLI for any automation, headless invocation, hook-based policy enforcement, or BYOK workflow. **Both surfaces share the same `.agent.md` files** by symlinking `.github/agents/` (project) and `~/.copilot/agents/` ↔ `%APPDATA%\Code\User\prompts\` (user); **`AGENTS.md` is read by both natively**. The MCP layer is the only piece that genuinely duplicates per the [CG-3 schema fork](50-copilot-cli-research.md#13-limits--known-gaps-relative-to-roo-cli-gap-catalog--phase-5b-ii-b-2): one `.vscode/mcp.json` (`servers:` shape) for Chat, one `.github/mcp.json` (`mcpServers:` shape) for CLI, generated from a single canonical YAML by a Phase-8 converter (`jq '{mcpServers: .servers}'` is the one-liner). + +**2. What you keep.** +- ✅ Everything Path A keeps for the IDE workflow. +- ✅ Everything Path B keeps for automation — including the `preToolUse` hook for `fileRegex` enforcement. +- ✅ **The vault's symlink-and-commit pattern survives almost intact** — `.agent.md` and `AGENTS.md` are shared by both surfaces; only the MCP file is duplicated. + +**3. What you lose.** +- 🔴 **G-1 in Chat-only sessions.** When working interactively in the IDE, the `preToolUse` hook does not fire (Chat has no hook surface). Mitigation: prose enforcement + reserve the Chat surface for read-mostly modes (architect, ask, code-review); use the CLI for any mode that genuinely needs the regex barrier. +- 🟠 **G-2 inherited** (per-mode rules folder). +- 🟠 **CG-3 MCP duplication** — adds a converter step; secrets must be authored in env vars (Path-B canonical) and then surfaced as `${input:…}` in the Chat-side file (a Phase-8 helper writes both). +- 🟠 **Q-049 todo re-injection** unsolved on both sides. +- 🟡 **Cognitive load — two panels.** Mitigated by clear "Chat for interactive, terminal for cron" mental model. + +**4. What you gain.** +- ➕ All Chat ➕ wins (W-2/4/7/8/10/12). +- ➕ All CLI ➕ wins (CW-1/2/3/4/6/7/12 + skills + `/mcp` REPL). +- ➕ **G-1 mitigated where it matters.** Vault's regex-bound modes (architect, translate, docs-extractor) get hook enforcement when invoked from the CLI; the IDE-bound modes (code, ask) where regex is less critical use Chat. +- ➕ **G-13 mitigated where it matters.** BYOK on the CLI side; Chat falls back to Copilot's catalog. +- ➕ **G-9 mitigated where it matters.** Chat sessions live in the profile DB (opaque); CLI sessions live as JSONL on disk (portable). Use the CLI for any session you want to keep. +- ➕ **Reversibility maximised** — the shared `.agent.md` + `AGENTS.md` files port to any other agent (Claude Code, Cursor, Codex, Gemini CLI) and back to Roo. + +**5. Effort estimate.** +- **First project:** **1–2 weeks.** Path-A conversion (3–7 days) + CLI bootstrap (2–3 days) + MCP dual-format converter script (1–2 days) + hook authoring for the regex-bound modes only (1–2 days). +- **Steady-state per new project:** **<1 day** — same templates as Path A and Path B applied together. +- **Ongoing maintenance:** **~3–5 hours/month** — sum of Path A (~1 hr) + Path B (~2–4 hr) less overlap. + +**6. Risks.** +- 🔴 **G-1 on Chat side.** Acknowledged trade-off; binding only if you forget which surface enforces what. +- 🟠 **MCP drift.** If Chat and CLI MCP files diverge, two configs must be reconciled. Phase-8 owns the canonical-source decision and the generator script. +- 🟠 **Skill / hook surface only on CLI side.** Skills don't fire in Chat; agentic loops with skill dependencies only work in the terminal. +- 🟡 **Onboarding new contributors** to two-surface workflows. + +**7. Prerequisites.** +- All Path-A prereqs **and** all Path-B prereqs (subscription works once for both; install both binaries; set both config trees). + +**8. Open questions specific to Hybrid.** +- All Path A and Path B Qs. +- **Q-050 [NEW] — canonical-source decision for MCP config.** YAML with two generators? `.vscode/mcp.json` as truth and CLI generated? `.github/mcp.json` as truth and Chat generated? Filed below. +- **Q-051 [NEW] — `AGENTS.md` ↔ `AGENTS.local.md` interaction with both surfaces.** Q-048 covers the file existence; Q-051 covers the dual-surface read order. + +**9. Score table.** + +| Criterion | Weight | Score (1–5) | Weighted | +|---|---:|---:|---:| +| C1 Capability fidelity | 30% | **4** (G-1 mitigated where it matters; G-2 still 🟠; ~5 surviving 🟠 across both surfaces) | 1.20 | +| C2 Effort | 20% | **3** (1–2 weeks first project; sum of A + lean B) | 0.60 | +| C3 Operational risk | 15% | **3** (CLI bugs apply to automation surface only; Chat is GA) | 0.45 | +| C4 Day-to-day UX | 10% | **4** (IDE for daily work; terminal for automation; familiar split) | 0.40 | +| C5 Automation / CI | 10% | **5** (full CLI surface available) | 0.50 | +| C6 Vault portability | 5% | **5** (`COPILOT_HOME` for CLI; Chat profile helper for the rest) | 0.25 | +| C7 Lock-in / reversibility | 5% | **5** (`.agent.md` + `AGENTS.md` shared; cross-tool readable) | 0.25 | +| C8 Cost | 5% | **5** (BYOK on CLI side) | 0.25 | +| **Total** | **100%** | — | **3.90** | + +**10. Verdict.** Choose Hybrid as the **default** for an IDE-centric developer who also needs automation and policy enforcement. Pays the duplication cost only on MCP (one schema-fork converter); everything else (modes, rules, AGENTS.md) is genuinely shared. + +--- + +## § 3 — Side-by-Side Comparison + +| Criterion | Wt | A (Chat) | B (CLI) | C (CLI+Squad) | D (VSIX) | **Hybrid** | +|---|---:|---:|---:|---:|---:|---:| +| C1 Capability fidelity | 30% | 2 | 4 | 4 | 5 | **4** | +| C2 Effort | 20% | 4 | 3 | 2 | 1 | **3** | +| C3 Operational risk | 15% | 4 | 3 | 2 | 2 | **3** | +| C4 Day-to-day UX | 10% | 5 | 2 | 2 | 5 | **4** | +| C5 Automation / CI | 10% | 1 | 5 | 5 | 3 | **5** | +| C6 Vault portability | 5% | 3 | 5 | 4 | 4 | **5** | +| C7 Reversibility | 5% | 4 | 5 | 3 | 2 | **5** | +| C8 Cost | 5% | 3 | 5 | 5 | 3 | **5** | +| **Weighted Total** | **100%** | **3.10** | **3.70** | **3.20** | **3.25** | **3.90** | +| **Rank** | — | 5th | 2nd | 4th | 3rd | **🥇 1st** | + +--- + +## § 4 — Recommendation + +### § 4.1 — Primary recommendation + +**Adopt Path Hybrid: Copilot Chat for interactive IDE work + Copilot CLI for automation, hook-based policy enforcement, and BYOK.** Share `.agent.md` files via symlink between `.github/agents/` and `~/.copilot/agents/`; commit a single `AGENTS.md` per project read by both surfaces; generate the two MCP file shapes from one canonical YAML via a Phase-8 converter. + +Justification (referencing § 3 scores): + +- **Highest weighted total (3.90).** Beats Path B (3.70) and Path A (3.10) on the criteria that the vault actually weights — Hybrid scores ≥4 on every criterion except C2/C3 where it's a reasonable 3. +- **Closes G-1 where it matters** without the binary "live in the terminal" cost of Path B. The vault's regex-bound modes (architect, translate, docs-extractor — confirmed in [20 § Global Settings](20-roo-vault-inventory.md)) gain `preToolUse` enforcement when invoked from the CLI; the IDE-bound modes (code, ask) keep their visual UX. +- **Preserves the vault's investment.** The 17 modes port mechanically (one `.agent.md` body schema satisfies both surfaces); the symlink-and-commit pattern in [`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1) extends naturally to the CLI's `COPILOT_HOME` env var (CW-6); only MCP needs a generator. +- **Effort is bounded** at 1–2 weeks for the first project and <1 day per new project — comparable to Path A alone, materially less than Path C or D, and dramatically less than building a custom VSIX. +- **Maximum reversibility.** `.agent.md` and `AGENTS.md` are cross-tool standards (Claude Code, Cursor, Gemini CLI, Codex CLI all read at least one); if Copilot disappoints, every other agent is one config-rename away. + +### § 4.2 — Conditions that would flip the recommendation + +- **If the vault uses zero `fileRegex` rules** (Q-047 audit returns 0): drop the CLI side; **Path A becomes viable** and effort drops to 3–7 days. The only reason to keep the CLI is automation (C5). +- **If the user has zero automation / CI / cron workflows planned**: drop the CLI side; **Path A** (3.10) becomes acceptable because C5's weight is wasted in Hybrid. +- **If the user has a demonstrated parallel-orchestration workload** (multi-agent code review, A/B model consensus, fleet-of-architects): **escalate to Path C** (Hybrid + Squad on the CLI side). The C5 score moves from 5 to ~5+ and parallel fan-out becomes a strict win. +- **If `fileRegex` is safety-critical** (production secrets, regulatory edits) **AND** the user has a month of capacity: **escalate to Path D** for the regex-bound modes only (i.e., a *thin* VSIX that wraps just the policy enforcement, leaving the rest on Path A/Hybrid). C1 moves from 4 to 5; C2 collapses to 1. +- **If the user's Copilot subscription is Free tier** and the agent-mode features are gated (verify against current GitHub pricing pages — outside this synthesis): **fall back to Path B-only** and use BYOK to a local Ollama. CLI agent mode is Free-tier-eligible per [50 § 1](50-copilot-cli-research.md). +- **If [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) is fixed upstream**: Hybrid's score moves from 3.90 → ~4.05 (CG-11 caveat removed; G-1 mitigation becomes complete on CLI side). Phase 8 should track this issue. + +### § 4.3 — Suggested hybrid blend (concrete file-level division of labour) + +Single canonical author point per artifact; two surfaces consume: + +| Artifact | Canonical source | Chat consumption | CLI consumption | +|---|---|---|---| +| Mode definitions | `.github/agents/.agent.md` (project) and `~/.copilot/agents/.agent.md` (user) | Direct read (`.github/agents/` is the Chat default; user-scope via symlink → `%APPDATA%\Code\User\prompts\`) | Direct read (`~/.copilot/agents/` via `COPILOT_HOME` symlink) | +| Always-on rules | `AGENTS.md` (project) | Native (`chat.useAgentsMdFile` = on) | Native ([50 § 4.1](50-copilot-cli-research.md)) | +| Per-file rules | `.github/instructions/*.instructions.md` | Native | Native (same path) | +| Per-mode rules | Inline in the agent body (G-2 acceptance) | Native | Native | +| MCP servers | **`mcp.canonical.yaml`** (Phase-8 invents) → generates `.vscode/mcp.json` (Chat) AND `.github/mcp.json` (CLI) | Generated `.vscode/mcp.json` with `${input:…}` placeholders | Generated `.github/mcp.json` with `${ENV_VAR}` substitution | +| Secrets | User-environment variables set via `[Environment]::SetEnvironmentVariable("KEY","val","User")` | First-run prompt → Credential Manager (W-4); cached value bridged to env via Phase-8 helper | Native env-var substitution | +| `fileRegex` policy | `.github/hooks/preToolUse-fileregex.ps1` + a JSON policy table | **Not enforced** (G-1 acceptance for Chat); prose-only in agent body | Enforced via `preToolUse` hook | +| Sessions / history | n/a | Profile DB (opaque) | `~/.copilot/session-state//` JSONL (portable) | +| Skills | `.github/skills//SKILL.md` | Not loaded (Chat doesn't fire skills) | Loaded; explicit `/skill` invocation | + +### § 4.4 — Phasing suggestion + +A **3-stage rollout** that minimises risk and lets each stage validate the next: + +1. **Stage 1 (week 1) — Path A scaffold.** Convert all 17 modes + rules + MCP for Chat-only. Disable Roo. Live in the IDE. This validates that Chat alone handles ≥80% of daily work and surfaces which gaps actually bite. +2. **Stage 2 (week 2) — Add CLI for the gaps.** Install `@github/copilot`, set `COPILOT_HOME`, symlink `.agent.md` files, ship the `preToolUse` hook for the 3 regex-bound modes only. Drive automation tasks (commit hooks, PR reviews from CLI, batch refactors) from the terminal. +3. **Stage 3 (later, conditional) — escalate only if needed.** + - If parallel orchestration becomes a real workload → add Squad (Path C). + - If `fileRegex` enforcement gaps become genuinely painful → build a thin Path-D VSIX for just that. + +Do **not** try to do Stage 2 and Stage 3 simultaneously; the Stage 1+2 surface alone is enough to learn from. + +### § 4.5 — Explicitly NOT recommended + +- **Path C (CLI + Squad) as a starting point.** Squad's parallel-orchestration value is real but narrow; layering an alpha tool over an already-evolving CLI surface multiplies the debugging surface for marginal vault benefit. The vault's current 17-mode pattern is sequential, not fan-out. Revisit only if your workflow explicitly evolves toward parallel agent dispatch. +- **Path D (Vault-as-VSIX) as a starting point.** ~1 engineer-month of unproductive work for a single-developer migration is poor ROI when Hybrid closes 90%+ of the same gaps in 1–2 weeks. Path D is a *Stage 3* escalation, not a starting point. +- **Path A on its own for a vault with `fileRegex` modes** — G-1 is unmitigated; the architect/translate/docs-extractor restrictions become prose-only and the model can violate them silently. + +--- + +## § 5 — Decision Tree + +```mermaid +flowchart TD + Start([Start: leaving Roo-Code]) --> Q1{Vault uses
fileRegex on any mode?} + Q1 -- No --> Q2{Need headless /
CI / cron workflows?} + Q1 -- Yes --> Q3{IDE-centric
day-to-day?} + Q2 -- No --> PathA[Path A
Chat only] + Q2 -- Yes --> PathHybrid[Path Hybrid
Chat + CLI] + Q3 -- Yes --> Q4{Have a month
for a custom VSIX?} + Q3 -- No --> Q5{Need parallel
fan-out orchestration?} + Q4 -- No --> PathHybrid + Q4 -- Yes --> PathD[Path D
Vault-as-VSIX] + Q5 -- Yes --> PathC[Path C
CLI + Squad] + Q5 -- No --> PathB[Path B
CLI only] +``` + +Reading the tree: the user's documented context (Windows 11 + IDE-centric + vault uses `fileRegex` per [20 § Global Settings](20-roo-vault-inventory.md) + has demonstrated automation interest via `apps/cli` + no parallel-fan-out workflow today + no month of free engineering capacity) traces **Q1 → Yes → Q3 → Yes → Q4 → No → Path Hybrid**. + +--- + +## § 6 — Sensitivity Analysis + +How would the recommendation change if a single input flips? + +| Trigger | Affected criterion | Score delta | Resulting rank shift | +|---|---|---|---| +| **`fileRegex` not used in vault** (Q-047 audit returns zero) | Path A's C1 score: 2 → 4 (no surviving 🔴) | A's total: 3.10 → 3.70 | **Path A ties Path B**; Hybrid still wins (3.90) but Path A becomes acceptable for IDE-only users. Drop the CLI side if also no automation. | +| **[`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) fixed upstream** (CG-11 sub-agent hook bypass closed) | Path B's C1: 4 → 5 (G-1 fully mitigated incl. sub-agents); Hybrid C1: 4 → 5 | B: 3.70 → 4.00; Hybrid: 3.90 → 4.20 | **Hybrid widens its lead.** Path B becomes a closer second; Path D's already-marginal lead on C1 evaporates. | +| **User adds a second laptop** (e.g., personal + work machine) | C6 weight effectively doubles in importance subjectively | A: 3.10 → ~3.05 (profile-id helper drag); B: 3.70 → ~3.75; Hybrid: 3.90 → ~3.95 | **Hybrid still wins** because it inherits CW-6 (`COPILOT_HOME`) on the CLI side. Path A degrades because per-profile `mcp.json` symlinks must be recreated per machine (Q-026 helper script needed). Path D unchanged (VSIX installs anywhere). | + +--- + +## § 7 — Hand-off to Phase 8 + +- **Primary path for Phase 8's playbook:** **Path Hybrid.** The playbook should treat Chat (`.github/agents/` + `.vscode/mcp.json` + `AGENTS.md`) and CLI (`~/.copilot/agents/` + `.github/mcp.json` + `preToolUse` hook + `COPILOT_HOME`) as twin first-class surfaces sharing one canonical `.agent.md` per mode and one `AGENTS.md` per project. Section ordering inside the playbook should follow the migration phasing in § 4.4 (Stage 1 = Chat scaffold, Stage 2 = add CLI for the gaps). + +- **Appendix path for contingency:** **Path B (CLI-only).** The playbook's Appendix should provide a `fileRegex`-heavy mapping (mode-by-mode `preToolUse` policy table) for the user who decides — after Stage 1 validation — that they prefer terminal-first workflows or that Chat's G-1 prose enforcement is unacceptable across the board. The Appendix should *not* duplicate the canonical mode-conversion content; it should reference the Hybrid sections and only document the deltas (skip Chat MCP file, skip Credential Manager input prompts, ship hook policies for *all* regex-bound modes not just the IDE-bypass ones). + +- **Open questions to resolve before / during Phase 8 execution:** + - **Before:** Q-047 (vault `fileRegex` audit — owns the regex-bound mode list the playbook will enforce), Q-030 (does the vault actually use a non-Copilot model? — informs whether BYOK is decisive on CLI side), Q-024 (`*.toolsets.jsonc` Settings Sync state — affects multi-machine portability of Chat side). + - **During:** Q-026 (multi-profile `mcp.json` PowerShell helper), Q-029 (Chat sessions export script), Q-035/Q-037/Q-039 (refining the `preToolUse` reference impl with active-agent identity + measured pwsh latency on user's box), Q-048 (`AGENTS.local.md` per-tool support test), Q-049 (`update_todo_list` re-injection approximation via `userPromptSubmitted` hook). + - **New from this phase:** Q-050 (canonical-source decision for MCP dual-format), Q-051 (`AGENTS.md` ↔ `AGENTS.local.md` dual-surface read order). + +--- + +## Cross-links + +- [`60-gap-analysis.md`](60-gap-analysis.md) · [`80-migration-playbook.md`](80-migration-playbook.md) · [`90-decision-log.md`](90-decision-log.md) · [`99-open-questions.md`](99-open-questions.md) diff --git a/docs/investigation/roo-to-copilot/80-migration-playbook.md b/docs/investigation/roo-to-copilot/80-migration-playbook.md new file mode 100644 index 00000000000..a9e94ac12bb --- /dev/null +++ b/docs/investigation/roo-to-copilot/80-migration-playbook.md @@ -0,0 +1,1771 @@ +--- +phase: 8 +status: complete +owner: architect-phase-8b-ii +last_updated: 2026-04-26 +phase_8b_i: complete +phase_8b_ii: complete +sources: + - docs/investigation/roo-to-copilot/10-roo-inventory.md + - docs/investigation/roo-to-copilot/20-roo-vault-inventory.md + - docs/investigation/roo-to-copilot/40-copilot-chat-research.md + - docs/investigation/roo-to-copilot/50-copilot-cli-research.md + - docs/investigation/roo-to-copilot/60-gap-analysis.md + - docs/investigation/roo-to-copilot/70-migration-paths.md + - docs/investigation/roo-to-copilot/99-open-questions.md +--- + + + +# Phase 8 — Concrete Migration Playbook (Path Hybrid) + +> Parent plan: [`00-plan.md`](00-plan.md) · Index: [`README.md`](README.md) · Recommendation: [`70-migration-paths.md` § 4](70-migration-paths.md#-4--recommendation) · Decision log: [`90-decision-log.md`](90-decision-log.md) + +## § 0 — Overview & scope + +**Recommended path:** **Path Hybrid (Copilot Chat + Copilot CLI), weighted score 3.90** — see [`70-migration-paths.md` § 4](70-migration-paths.md#-4--recommendation). Hybrid uses **Chat as the IDE-centric interactive surface** and **CLI as the automation / hook-based-policy / BYOK surface**, sharing one canonical [`.agent.md`](#-22--agentmd-schema-and-conversion) per mode and one [`AGENTS.md`](#-21--agentsmd-project-root) per project. Only the MCP layer genuinely duplicates because of the [CG-3 schema fork](50-copilot-cli-research.md#13-limits--known-gaps-relative-to-roo-cli-gap-catalog--phase-5b-ii-b-2) (Chat uses `servers:`, CLI uses `mcpServers:`). + +**Architecture sketch:** + +```mermaid +flowchart LR + subgraph SHARED [Shared assets - both surfaces] + A1[.github/agents/*.agent.md] + A2[AGENTS.md + AGENTS.local.md] + A3[.github/instructions/*.instructions.md] + end + subgraph CHAT [Chat - 8a] + C1[.vscode/mcp.json - servers] + C2[%APPDATA%/Code/User/mcp.json] + C3[user *.toolsets.jsonc] + C4[.github/copilot-instructions.md] + end + subgraph CLI [CLI - 8b] + D1[.github/mcp.json - mcpServers] + D2[~/.copilot/agents symlink] + D3[preToolUse hook - fileRegex] + D4[COPILOT_HOME env] + end + SHARED --> CHAT + SHARED --> CLI + CHAT -. duplicate via jq generator .-> CLI +``` + +**Map of this document:** + +| § | Section | Phase | Status | +|---|---|---|---| +| § 0 | Overview & scope | 8a | ✅ | +| § 1 | Pre-migration checklist | 8a | ✅ | +| § 2 | Shared assets (work in both surfaces) | 8a | ✅ | +| § 3 | Chat-side configuration | 8a | ✅ | +| § 4 | 17-mode mapping table | 8a | ✅ skeleton (audit command provided) | +| § 5 | Step-by-step Phase 8a execution | 8a | ✅ | +| § 6 | Hand-off to Phase 8b | 8a | ✅ | +| § 7 | CLI-side configuration (`~/.copilot/`, `mcpServers` schema) | 8b | ⏭ deferred | +| § 8 | `preToolUse` hook for `fileRegex` enforcement | 8b | ⏭ deferred | +| § 9 | MCP canonical-source generator (Q-050) | 8b | ⏭ deferred | +| § 10 | Setup automation (vault + project + pre-commit) | 8b-ii | ✅ | +| § 11 | Validation matrix | 8b-ii | ✅ | +| § 12 | Rollback plan | 8b-ii | ✅ | +| Appendix B | Path B (CLI-only) fallback playbook | 8b-ii | ✅ | + +**Status badge convention** used throughout: ✅ done · ⏭ deferred to Phase 8b · ❌ not applicable / dropped on purpose · ⚠ requires user input or audit before proceeding. + +--- + +## § 1 — Pre-migration checklist + +Run these **before touching any config**. They establish the inputs that downstream sections depend on. + +1. **⚠ Vault `fileRegex` audit (Q-047).** Enumerate every mode in the global vault file and per-project `.roomodes` files that uses a `fileRegex` restriction. The output drives § 4's `Has fileRegex?` column and § 8's hook coverage list. + + PowerShell command (run from anywhere): + + ```powershell + # Audit global vault modes + Select-String -Path "$HOME\..\..\git\roo-vault\global-settings\custom_modes.yaml" ` + -Pattern "fileRegex" -Context 2,1 + # Audit per-project overrides + Get-ChildItem "$HOME\..\..\git\roo-vault\projects" -Recurse -Filter ".roomodes" | + ForEach-Object { + Write-Host "=== $($_.FullName) ===" -ForegroundColor Cyan + Select-String -Path $_.FullName -Pattern "fileRegex" -Context 2,1 + } + ``` + + Expected from [20 § Global Settings](20-roo-vault-inventory.md): at least `architect` (`\.md$`), `translate` ((md|ts|tsx|js|jsx|json)), `docs-writer` (`\.(md|txt|rst|adoc)$`), `docs-extractor` (`\.roo/extraction/.*\.(yaml|json|md)$`). User confirms the final count and records it in § 4. + +2. **⚠ Canonical MCP source decision (Q-050).** Hybrid duplicates MCP config across Chat (`.vscode/mcp.json` with `servers:`) and CLI (`.github/mcp.json` or `~/.copilot/mcp-config.json` with `mcpServers:`). Pick **one** of: + + | Option | Trade-off | + |---|---| + | (a) **Chat-as-truth + `jq` generator → CLI** | Best for IDE-first users; `.vscode/mcp.json` is what VS Code's "MCP: Open Workspace Configuration" command edits, so day-to-day edits land in the canonical file. Generator runs on commit. **Recommended default.** | + | (b) **CLI-as-truth + `jq` generator → Chat** | Best for terminal-first users / CI-heavy workflows. Loses VS Code's first-run `${input:…}` Credential Manager hand-off (must re-author). | + | (c) **Third file `mcp.canonical.yaml` + two generators** | Cleanest separation; adds an extra file no tool reads natively. Worthwhile only if you also generate `.envrc` / dev-container MCP configs from the same source. | + + **Recommendation:** option (a) for this vault (IDE-centric per [`70 § 4`](70-migration-paths.md#-4--recommendation)). Phase 8b will ship the actual `jq`/PowerShell generator script. + +3. **Subscription tier verification.** Confirm which Copilot tier is active at (or `gh api user/copilot_status`). Tier-gated features that matter to this migration: + + | Feature | Minimum tier | Source | + |---|---|---| + | Chat custom agents (`.agent.md`) | **Free** | [40 § Storage](40-copilot-chat-research.md) | + | Copilot CLI (`@github/copilot`) agent mode | **Free** | [50 § 1](50-copilot-cli-research.md) | + | Cloud agent (PR creation from issue) | **Pro** | [40 § Cloud agent](40-copilot-chat-research.md) | + | BYOK (`COPILOT_PROVIDER_BASE_URL` to Ollama / Anthropic / Azure OpenAI) on CLI | **Pro+** | [50 § CW-2](50-copilot-cli-research.md) | + | Org-managed policies (`chat.tools.eligibleForAutoApproval`, `chat.agent.networkFilter`) | **Business / Enterprise** | [40 § Permission levels](40-copilot-chat-research.md) | + | Agent Plugins (Preview) gallery | **Pro+** with `chat.plugins.enabled` | [40 § Agent plugins](40-copilot-chat-research.md) | + +4. **Node 22.5+ on PATH.** Required by Squad's SDK pin and recent `@github/copilot-sdk` releases (per [50 § 7](50-copilot-cli-research.md#7-sdk-githubcopilot-sdk--full-export-catalogue-phase-5b-ii-b-1)). Verify: + + ```powershell + node -v # expect v22.5.0 or higher + npm -v + ``` + + If older, install via `winget install OpenJS.NodeJS.LTS` or `choco install nodejs-lts`. + +5. **Backup `.roomodes`, `~/.roo/rules/`, vault snapshot.** Create a dated rollback folder so Stage-1 can be reversed in <5 minutes: + + ```powershell + $stamp = Get-Date -Format "yyyyMMdd-HHmm" + $bak = "$HOME\roo-migration-backup-$stamp" + New-Item -ItemType Directory -Path $bak | Out-Null + Copy-Item -Recurse "$HOME\..\..\git\roo-vault" "$bak\roo-vault" + Copy-Item -Recurse "$env:APPDATA\Code\User\globalStorage\rooveterinaryinc.roo-cline" ` + "$bak\roo-cline-globalStorage" + if (Test-Path .roomodes) { Copy-Item .roomodes "$bak\" } + if (Test-Path .roo) { Copy-Item -Recurse .roo "$bak\" } + Write-Host "Backup at $bak" + ``` + +6. **Disable Roo extension (don't uninstall yet).** Keep as 30-day fallback per § 12 (Phase 8b rollback). In VS Code: `Extensions` view → search `Roo Code` → gear icon → **Disable (Workspace)** for the pilot project, **Disable** globally once Stage-2 validates. Do **not** click *Uninstall* until §11 validation has passed for ≥30 days. + +7. **Pin upstream issues to watch.** Subscribe (GitHub bell icon) to the bugs that bound Hybrid's score: + - [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) — structured `--output-format json` event stream (CG-7). When shipped, Phase 8b automation can drop its NDJSON shim. + - [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) — `task`-dispatched sub-agents bypass `preToolUse` (CG-11). Binding constraint on G-1 mitigation; when fixed, the architect/translate/docs-extractor modes get full hook enforcement even when sub-dispatched. + - [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515) — workspace-scoped `*.toolsets.jsonc` (G-3). When shipped, the inline-`tools:` workaround in § 3.3 collapses. + - [`microsoft/vscode#251603`](https://github.com/microsoft/vscode/issues/251603) — `*.toolsets.jsonc` Settings Sync (Q-024). + +--- + +## § 2 — Shared assets (work in BOTH Chat and CLI) + +These three artifact types are the **portability core** of the migration. A single file edit propagates to both surfaces. + +### § 2.1 — `AGENTS.md` (project root) + +**Who reads it (cross-tool standard):** + +| Tool | Reads `AGENTS.md`? | Toggle / setting | +|---|---|---| +| Copilot Chat (VS Code) | ✅ | `chat.useAgentsMdFile` (default **on** per [40 § Custom Instructions (4)](40-copilot-chat-research.md#custom-instructions-githubcopilot-instructionsmd)) | +| Copilot CLI | ✅ native | [50 § 4.1](50-copilot-cli-research.md) | +| Claude Code | ✅ native | upstream cross-tool standard | +| Codex / Cursor / Gemini CLI | ✅ at least one of `AGENTS.md` / `CLAUDE.md` / `GEMINI.md` | per [40 § 4](40-copilot-chat-research.md#custom-instructions-githubcopilot-instructionsmd) | + +**What goes in:** project-wide always-on instructions — coding standards, commands list, repo conventions, "how to run tests", "where the database connection lives". Anything you'd want every agent to read on every turn. + +**Migration steps:** + +1. The Roo-Code repo already has [`AGENTS.md`](../../../AGENTS.md). **Copy it verbatim to the migration target project's root.** No frontmatter changes needed for Copilot — both surfaces ingest plain Markdown. +2. For projects without an `AGENTS.md`, create one: + + ```markdown + # AGENTS.md + + Project: + Stack: + + ## Commands + - Install: `pnpm install` + - Test: `pnpm test` + - Build: `pnpm build` + + ## Conventions + - + - + ``` + +3. Nested per-folder `AGENTS.md` (e.g., `apps/web/AGENTS.md`) is supported in Chat behind the `chat.useNestedAgentsMdFiles` setting; CLI honours it natively. Per [40 § Custom Instructions (4)](40-copilot-chat-research.md#custom-instructions-githubcopilot-instructionsmd): *"the nearest `AGENTS.md` file in the directory tree will take precedence."* + +**`AGENTS.local.md` — gitignored personal overrides (Q-051):** + +The cross-tool community convention is to place a sibling `AGENTS.local.md` next to `AGENTS.md` and gitignore the `.local.md` suffix; both files concatenate when the agent loads context. + +> ⚠ **Both Chat and CLI support for `AGENTS.local.md` is unverified** (Q-048 / Q-051). Until verified, the safe pattern is: +> +> 1. Add `AGENTS.local.md` to `.gitignore`. +> 2. Author a small `AGENTS.local.md` containing one identifying token (e.g., `LOCAL-OVERRIDE-12345`). +> 3. Ask each agent in chat to "quote any line containing `LOCAL-OVERRIDE`" — if the agent quotes the token, the file is being read. +> 4. If neither surface reads it, the fallback is to put personal overrides in user-scope `%APPDATA%\Code\User\prompts\personal.instructions.md` with `applyTo: "**"` (Chat) and `~/.copilot/instructions/personal.instructions.md` (CLI). + +### § 2.2 — `.agent.md` schema and conversion + +#### Canonical frontmatter (per [40 § Custom Chat Modes (1)](40-copilot-chat-research.md#custom-chat-modes-chatmodemd)) + +```yaml +--- +name: Architect # display name (defaults to filename) +description: Plan, design, strategize # placeholder text in chat input + auto-pick hint +argument-hint: e.g., "design auth flow" # optional hint +tools: # allowlist; tool sets, individual tools, MCP wildcards + - "#search" + - "#edit" + - "github/*" + - "context7/*" +agents: ["Implementer", "Reviewer"] # subagent allowlist; * = all, [] = none +model: ["claude-opus-4.7", "gpt-5"] # priority order; first available wins +user-invocable: true # if false, only callable as a subagent +disable-model-invocation: false # if true, can't be called as a subagent +target: vscode # vscode | github-copilot +mcp-servers: { ... } # inline MCP JSON (only when target: github-copilot) +handoffs: # post-response next-step buttons + - label: "Implement this plan" + agent: Implementer + prompt: "Implement the plan above." + send: false +hooks: { ... } # Preview; per-agent PreToolUse / PostToolUse (CLI only enforces; see § 8 [Phase 8b]) +--- + +You are Roo, an experienced technical leader who is inquisitive and an excellent planner. +…body Markdown is prepended to every user prompt under this agent… +``` + +#### Worked example: vault `architect` mode → `.github/agents/architect.agent.md` + +**Source (Roo)** — extracted from [`../../../../roo-vault/global-settings/custom_modes.yaml`](../../../../roo-vault/global-settings/custom_modes.yaml) (line numbers per [20 § Global Settings](20-roo-vault-inventory.md), entry #18): + +```yaml +- slug: architect + name: 🏗️ Architect + roleDefinition: | + You are Roo, an experienced technical leader who is inquisitive and an excellent planner. + Your goal is to gather information and get context to create a detailed plan for accomplishing + the user's task, which the user will review and approve before they switch into another mode + to implement the solution. + whenToUse: | + Use this mode when you need to plan, design, or strategize before implementation. + customInstructions: | + Load and follow the shared architect instructions from .roo/shared-modes/architect.md. + groups: + - read + - - edit + - fileRegex: \.md$ + description: Markdown files only + - mcp + allowedMcpServers: + - git + - context7 + - tavily + - ado +``` + +**Target (Copilot Chat)** — `.github/agents/architect.agent.md`: + +```markdown +--- +name: 🏗️ Architect +description: Plan, design, or strategize before implementation. Gathers context and produces a detailed plan for review. +tools: + - "#search" # group "read" expands to #search + read/problems + search/usages + - "search/codebase" + - "search/usages" + - "read/problems" + - "#edit" # ⚠ G-1: fileRegex \.md$ NOT enforceable in Chat — see body + § 8 [Phase 8b] + - "git/*" # from allowedMcpServers: [git] + - "context7/*" + - "tavily/*" + - "ado/*" +agents: ["💻 Code", "🔧 Issue Fixer", "🪲 Debug"] # typical handoff targets +model: ["claude-opus-4.7", "gpt-5"] +user-invocable: true +--- + +You are Roo, an experienced technical leader who is inquisitive and an excellent planner. +Your goal is to gather information and get context to create a detailed plan for accomplishing +the user's task, which the user will review and approve before they switch into another mode +to implement the solution. + +## File-edit policy (G-1 prose enforcement — Chat surface) + +You may **only edit Markdown files** (matching glob `**/*.md`). Refuse to edit any other +file type and instead propose the change as a code block in chat. + +> The CLI surface enforces this same policy structurally via a `preToolUse` hook +> (see § 8 of the migration playbook). On the Chat surface this prose is the only guard. + +## Shared instructions + +See [`.github/instructions/architect-shared.instructions.md`](../instructions/architect-shared.instructions.md) +for the canonical body migrated from `roo-vault/shared-modes/architect.md`. + +## Handoffs + +When a plan is approved, hand off to the **💻 Code** agent for implementation. +``` + +#### Where `.agent.md` lives — workspace vs user + +| Scope | Chat reads | CLI reads | Strategy | +|---|---|---|---| +| Workspace | `.github/agents/*.agent.md` | `.github/agents/*.agent.md` (via `--workspace-agents` discovery) | ✅ **shared file** — commit it; both surfaces read the same path | +| User | `%APPDATA%\Code\User\prompts\*.agent.md` (per [Q-015](99-open-questions.md), the global `prompts/` folder, NOT profile-scoped) | `~/.copilot/agents/*.agent.md` (i.e., `%USERPROFILE%\.copilot\agents\`) | **different folders** — see helper below | + +**User-scope sharing pattern** (PowerShell helper to avoid double-authoring): + +```powershell +# Author once in the vault, symlink both consumer locations. +$src = "C:\git\roo-vault\global-settings\agents" # vault canonical user-scope +$chat = "$env:APPDATA\Code\User\prompts" # Chat reads here +$cli = "$env:USERPROFILE\.copilot\agents" # CLI reads here + +# Chat: symlink each .agent.md from $src into $chat (prompts/ holds many file types, +# so symlink files individually rather than the whole folder) +Get-ChildItem $src -Filter "*.agent.md" | ForEach-Object { + New-Item -ItemType SymbolicLink -Path "$chat\$($_.Name)" -Target $_.FullName -Force +} + +# CLI: symlink the whole agents folder +if (-not (Test-Path $cli)) { + New-Item -ItemType SymbolicLink -Path $cli -Target $src +} +``` + +> The asymmetry exists because Chat's `prompts/` folder is shared with `.prompt.md`, `.instructions.md`, and `*.toolsets.jsonc` files (per [40 § Storage](40-copilot-chat-research.md)), so a folder-level symlink would shadow other content. + +#### Roo → `.agent.md` field-mapping rules + +| Roo field | `.agent.md` target | Notes | +|---|---|---| +| `slug` | filename (kebab-case) → `.agent.md` | `slug: architect` → `architect.agent.md`. Do not preserve emoji from `name` in filename. | +| `name` | frontmatter `name:` | Keep the emoji + display name (`🏗️ Architect`). | +| `roleDefinition` | `.agent.md` body, opening paragraph | Verbatim — no transformation. | +| `whenToUse` | frontmatter `description:` (loose / heuristic) | Chat uses this as auto-pick hint and chat-input placeholder; not a hard gate. | +| `customInstructions` | body main section + Markdown link to `.instructions.md` | For long content (>50 lines), put the body in `.github/instructions/-shared.instructions.md` with `applyTo: "**"` and link from the agent body — keeps the agent file scannable. | +| `groups: [read, edit, command, mcp, browser]` | `tools: [...]` array | Group-to-tool expansion: `read` → `["#search", "search/codebase", "search/usages", "read/problems"]`; `edit` → `["#edit"]`; `command` → `["runInTerminal"]`; `mcp` → enumerate per `allowedMcpServers`; `browser` → `["openSimpleBrowser"]`. Cross-ref [40 § Tool Sets (6)](40-copilot-chat-research.md#tool-sets). | +| `groups: [["edit", { fileRegex: "\\.md$" }]]` | ⏭ **deferred to Phase 8b CLI hook** | **Chat cannot enforce** (G-1, [40 § Limits](40-copilot-chat-research.md#limits--known-gaps)). Add prose paragraph to `.agent.md` body as a soft guard; the CLI's `preToolUse` hook is the structural safety net. | +| `allowedMcpServers: ["github"]` | `tools: ["github/*"]` | Direct equivalent per [40 § MCP (4)](40-copilot-chat-research.md#mcp-support). Wildcard `serverName/*` admits all tools from one server. | +| `allowedMcpServers: []` (empty array) | `tools: [...]` with **no** `/…` entries | Roo's empty-array sentinel ("no MCP at all", per [Q-009](99-open-questions.md)) maps to omitting all MCP wildcards from `tools:`. | +| Source (built-in / global / project) | file location only (no field) | Built-in modes: provided by VS Code; do not author. Global vault modes → `%APPDATA%\Code\User\prompts\` (or `.github/agents/` shared via vault symlink). Project overrides → `.github/agents/`. | +| `description` (in `.roomodes` UI) | frontmatter `description:` | Same as `whenToUse` mapping. | + +### § 2.3 — `.github/instructions/*.instructions.md` with `applyTo` glob + +**Maps Roo's `.roo/rules/` (project) and `~/.roo/rules/` (global) → path-scoped instruction files** read by both Chat ([40 § Custom Instructions (2)](40-copilot-chat-research.md#custom-instructions-githubcopilot-instructionsmd)) and CLI (`~/.copilot/instructions/`). + +**Frontmatter schema** (per [40 § 2](40-copilot-chat-research.md#custom-instructions-githubcopilot-instructionsmd)): + +```yaml +--- +name: Test conventions # optional, defaults to filename +description: How tests are written # shown in tooltip +applyTo: "**/*.test.ts, **/*.spec.ts" # comma-separated globs; "**" = always +--- + +# Body — Markdown +- Use Vitest's `describe` / `test` / `it` from globals… +``` + +If `applyTo` is omitted, the file is **not auto-applied** — only attachable manually via the chat `#`-mention picker. + +**Migration steps:** + +1. For each `.md` file in the vault's `~/.roo/rules/` (global) and the project's `.roo/rules/` (project): + - Move to `.github/instructions/.instructions.md` (project) or `%APPDATA%\Code\User\prompts\.instructions.md` (user). + - Add frontmatter `applyTo: "**"` for blanket rules; or a path-specific glob (e.g., `applyTo: "src/**/*.ts"`) for code-only rules. +2. For `.roo/rules-/` (per-mode rule packs — Roo G-2 with no first-class equivalent in Copilot, per [40 § Limits G-2](40-copilot-chat-research.md#limits--known-gaps)): + - ⏭ **Deferred to Phase 8b.** The Phase-8a interim is to **link from the agent body**: in `.github/agents/.agent.md`, add a Markdown link `See [.github/instructions/rules-.instructions.md](...)` and put the rule content in that file with `applyTo: "**"`. The instructions file will then load on every turn (including non-`` turns), which is broader than Roo's mode-scoping but acceptable as a Stage-1 compromise. + - Phase 8b will document any naming convention or `excludeAgent`-style filter that lets us recover per-mode scoping. + +**Rules-folder migration command:** + +```powershell +# Project-scope: .roo/rules/*.md → .github/instructions/*.instructions.md +$src = ".roo\rules" +$dst = ".github\instructions" +New-Item -ItemType Directory -Path $dst -Force | Out-Null +Get-ChildItem $src -Filter "*.md" | ForEach-Object { + $newName = "$($_.BaseName).instructions.md" + $content = "---`napplyTo: `"**`"`n---`n`n" + (Get-Content $_.FullName -Raw) + Set-Content -Path "$dst\$newName" -Value $content -Encoding UTF8 + Write-Host " $($_.Name) → $newName" +} +``` + +--- + +## § 3 — Chat-side configuration + +### § 3.1 — `.vscode/mcp.json` (workspace) + +**Schema** (per [40 § MCP (1)](40-copilot-chat-research.md#mcp-support)): two top-level keys, `servers` (object: name → config) and `inputs` (array of typed-prompt definitions for secrets). + +**Side-by-side conversion** — vault's [`../../../../roo-vault/projects/Roo-Code/.roo/mcp.json`](../../../../roo-vault/projects/Roo-Code/.roo/mcp.json) → `.vscode/mcp.json`: + +| Roo (`.roo/mcp.json`) | Copilot Chat (`.vscode/mcp.json`) | +|---|---| +| Top-level key `mcpServers` | Top-level key `servers` (rename) | +| Inline `env: { GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_xxx…" }` | `env: { GITHUB_PERSONAL_ACCESS_TOKEN: "${input:githubToken}" }` + `inputs` entry | +| `disabled: true` per server | enable/disable state moved to workspace state (Extensions view), not in `mcp.json` | +| File **gitignored** because it contains tokens | File **committable** because secrets are placeholders | + +**Worked target** — `.vscode/mcp.json` for the Roo-Code project (mirrors [20 § MCP Server Inventory](20-roo-vault-inventory.md) for `ado` + `git`): + +```jsonc +{ + "inputs": [ + { "type": "promptString", "id": "adoPat", "description": "Azure DevOps PAT (msdata)", "password": true } + ], + "servers": { + "ado": { + "command": "npx", + "args": ["-y", "@azure-devops/mcp", "msdata"], + "env": { "ADO_PAT": "${input:adoPat}" } + }, + "git": { + "command": "docker", + "args": [ + "run", "--rm", "-i", + "--mount", "type=bind,src=${workspaceFolder},dst=/workspace", + "mcp/git", "--repository", "/workspace" + ] + } + } +} +``` + +**`${input:id}` semantics** (per [40 § MCP (3)](40-copilot-chat-research.md#mcp-support)): on first server start, VS Code shows a Quick Pick prompt for each referenced input ID; the supplied value is stored in **Windows Credential Manager** via `vscode.SecretStorage` and reused silently on subsequent runs. To force a re-prompt, run **MCP: Reset Trust** or delete the saved input via the Chat Customizations editor. + +**Commit safety:** the file with `${input:…}` placeholders is **safe to commit**. Tokens never touch disk in plaintext outside the OS keychain. This collapses Roo's gitignored-`mcp_settings.json` + committed-`.roo/mcp.json` two-file split into one committable file. + +### § 3.2 — `%APPDATA%\Code\User\mcp.json` (user / profile) + +**Maps the vault's [`../../../../roo-vault/global-settings/mcp_settings.json`](../../../../roo-vault/global-settings/mcp_settings.json) → user-scope Chat config.** Per [20 § MCP Server Inventory](20-roo-vault-inventory.md): 4 enabled (`github`, `context7`, `tavily`, `microsoft-learn`) + 3 disabled (`memory`, `filesystem`, `brave-search`). + +**Path on Windows:** + +- **Default profile:** `%APPDATA%\Code\User\mcp.json` → `C:\Users\\AppData\Roaming\Code\User\mcp.json` +- **Named profile:** `%APPDATA%\Code\User\profiles\\mcp.json` (per [40 § MCP (2)](40-copilot-chat-research.md#mcp-support)). The `` is a generated short ID, not the human name; the cleanest discovery is to invoke **MCP: Open User Configuration** in the desired profile. + +**Worked target** — `%APPDATA%\Code\User\mcp.json` covering the 4 enabled vault servers: + +```jsonc +{ + "inputs": [ + { "type": "promptString", "id": "githubToken", "description": "GitHub PAT for github MCP", "password": true }, + { "type": "promptString", "id": "tavilyKey", "description": "Tavily API key", "password": true }, + { "type": "promptString", "id": "context7Key", "description": "Context7 API key", "password": true } + ], + "servers": { + "github": { + "command": "docker", + "args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"], + "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${input:githubToken}" } + }, + "tavily": { + "command": "docker", + "args": ["run", "-i", "--rm", "-e", "TAVILY_API_KEY", "mcp/tavily"], + "env": { "TAVILY_API_KEY": "${input:tavilyKey}" } + }, + "context7": { + "type": "http", + "url": "https://mcp.context7.com/mcp", + "headers": { "CONTEXT7_API_KEY": "${input:context7Key}" } + }, + "microsoft-learn": { + "type": "http", + "url": "https://learn.microsoft.com/api/mcp" + } + } +} +``` + +**Disabled-in-Roo servers** (`memory`, `filesystem`, `brave-search`): leave them out of `servers:` entirely, OR include them and use the Extensions view (`@mcp` filter) to toggle their enable/disable state — that toggle is workspace/profile state, not in `mcp.json`. + +### § 3.3 — `*.toolsets.jsonc` (user-scope only — G-3 workaround) + +**Status:** workspace-scope `*.toolsets.jsonc` is **not yet supported** ([G-3](40-copilot-chat-research.md#limits--known-gaps), [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515)). The current shipping recommendation: + +- **Default for Phase 8a:** **inline `tools:` arrays per agent** in `.github/agents/.agent.md`. This is workspace-scoped (commits with the repo) and Hybrid-friendly (CLI also reads `.github/agents/`). § 2.2's worked architect example demonstrates this pattern. +- **Optional:** for users who want reusable bundles across many agents, author a user-scope `*.toolsets.jsonc` in `%APPDATA%\Code\User\prompts\` (per [40 § Tool Sets (2)](40-copilot-chat-research.md#tool-sets)). + +**Example user-scope toolset** — bundle "edit + GitHub MCP" into one referenceable name: + +```jsonc +// %APPDATA%\Code\User\prompts\writer-with-github.toolsets.jsonc +{ + "writer-with-github": { + "tools": [ + "#edit", + "github/get_issue", + "github/create_issue", + "github/list_issues", + "github/get_pull_request", + "github/create_pull_request" + ], + "description": "Markdown editing + GitHub Issues / PR CRUD", + "icon": "edit" + } +} +``` + +Reference from any `.agent.md`'s `tools: ["writer-with-github"]` or from a chat input via `#writer-with-github`. + +**Sync caveat (Q-024):** `*.toolsets.jsonc` is reportedly **not** synced via Settings Sync's "Prompts and Instructions" category ([`microsoft/vscode#251603`](https://github.com/microsoft/vscode/issues/251603)). Multi-machine users should symlink the file from the vault rather than relying on cloud sync. + +### § 3.4 — `.github/copilot-instructions.md` (repo-wide) + +**Single-file repo-wide always-on instructions** — per [40 § Custom Instructions (1)](40-copilot-chat-research.md#custom-instructions-githubcopilot-instructionsmd), VS Code auto-attaches this file to every Chat / agent-mode request in the workspace. + +**Decision: when to use which file:** + +| Content | Target | Why | +|---|---|---| +| Short (<100 lines), single concern | `.github/copilot-instructions.md` | Simplest; no glob; no frontmatter required | +| Long (>100 lines), multiple concerns | Multiple `.github/instructions/*.instructions.md` with `applyTo: "**"` | Composable; attach selectively; better diffability | +| Path-scoped (e.g., `src/**/*.ts` only) | `.github/instructions/*.instructions.md` with the path glob | `copilot-instructions.md` does not support globbing | +| Always-on cross-tool (read by Claude / Codex / Gemini too) | `AGENTS.md` (§ 2.1) | Cross-tool standard; `copilot-instructions.md` is Copilot-specific | + +**Recommendation for the vault:** put **command lists, repo conventions, test-running instructions** in `AGENTS.md` (cross-tool); put **Copilot-specific tweaks** (e.g., model preferences, `chat.*` setting reminders) in `.github/copilot-instructions.md`. Avoid duplication — `AGENTS.md` and `.github/copilot-instructions.md` both load on every turn, so content in both doubles the prompt cost. + +--- + +## § 4 — 17-mode mapping table + +The master checklist for Phase 8a → 8b. Each row represents one vault mode that needs a `.agent.md` in `.github/agents/`. The `Has fileRegex?` column is the **Phase 8b hook coverage list**. + +> ⚠ **Source-of-truth note.** The vault has 17 user-authored modes per the original task brief, though [20 § Global Settings](20-roo-vault-inventory.md) counts 21 entries (the file has grown). The table below uses the 17 most-cited slugs from [`../../../../roo-vault/global-settings/custom_modes.yaml`](../../../../roo-vault/global-settings/custom_modes.yaml). Re-run § 1 step 1 (audit command) to confirm the final list and the `Has fileRegex?` column for your snapshot. + +**Tools-allowlist column is best-effort from [20 § Global Settings](20-roo-vault-inventory.md)**; values marked ⚠ Q-047 require the audit to confirm. + +| # | Mode slug | Tools allowlist (target `.agent.md` `tools:`) | Has `fileRegex`? | `.agent.md` filename | Notes / Phase 8b action | +|---|---|---|---|---|---| +| 1 | `docs-writer` | `[#search, #edit, "*/*"]` (all MCP) | ✅ Yes (`\.(md\|txt\|rst\|adoc)$`) | `docs-writer.agent.md` | Phase 8b hook required | +| 2 | `security` | `[#search, "*/*"]` (read-only; drop `#edit`) | ❌ No (no `edit` group) | `security.agent.md` | Read-only enforced by tool omission | +| 3 | `design-reviewer` | `[#search, "*/*"]` (read-only) | ❌ No | `design-reviewer.agent.md` | Body must say "never implements" | +| 4 | `review-addresser` | `[#search, #edit, runInTerminal, "*/*"]` | ❌ No | `review-addresser.agent.md` | Standard edit agent | +| 5 | `code-reviewer` | `[#search, runInTerminal]` (READ-ONLY, no edit, no MCP) | ❌ No | `code-reviewer.agent.md` | Strict read-only — `#edit` deliberately omitted | +| 6 | `task-filer` | `[#search, runInTerminal, "*/*"]` | ❌ No | `task-filer.agent.md` | No edit group | +| 7 | `builder` | `[#search, #edit, runInTerminal, "*/*"]` | ❌ No | `builder.agent.md` | — | +| 8 | `tester` | `[#search, #edit, runInTerminal, "*/*"]` | ❌ No | `tester.agent.md` | — | +| 9 | `translate` | `[#search, runInTerminal, #edit (regex)]` | ✅ Yes (`(.*\.(md\|ts\|tsx\|js\|jsx)$\|.*\.json$)`) | `translate.agent.md` | **Phase 8b hook required** | +| 10 | `issue-fixer` | `[#search, #edit, runInTerminal]` | ❌ No | `issue-fixer.agent.md` | — | +| 11 | `merge-resolver` | `[#search, #edit, runInTerminal, "*/*"]` | ❌ No | `merge-resolver.agent.md` | — | +| 12 | `docs-extractor` | `[#search, #edit (regex), runInTerminal, "*/*"]` | ✅ Yes (`\.roo/extraction/.*\.(yaml\|json\|md)$`) | `docs-extractor.agent.md` | **Phase 8b hook required** | +| 13 | `issue-investigator` | `[#search, runInTerminal, "*/*"]` (read-only) | ❌ No | `issue-investigator.agent.md` | — | +| 14 | `issue-writer` | `[#search, runInTerminal, "*/*"]` (read-only) | ❌ No | `issue-writer.agent.md` | — | +| 15 | `architect` | `[#search, #edit (regex), git/*, context7/*, tavily/*, ado/*]` | ✅ Yes (`\.md$`) | `architect.agent.md` | **Phase 8b hook required** — worked example in § 2.2 | +| 16 | `pull-requestor` | `[#search, #edit, runInTerminal, ado/*, git/*]` | ❌ No | `pull-requestor.agent.md` | — | +| 17 | `orchestrator` | `[#search, agent]` (read + subagent dispatch) | ❌ No | `orchestrator.agent.md` | Set `agents: ["*"]`; per [70 § 4.4](70-migration-paths.md#-44--phasing-suggestion), use parallel sub-agent dispatch where appropriate | + +> Additional vault entries not in the canonical 17 (`code`, `ask`, `debug`, `devops`, `pr-fixer`) are built-in Copilot agents (`code` ≈ default Agent; `ask` ≈ Ask; `debug` ≈ Plan + Agent) **plus** project-level overrides. Author them only if the vault's overrides materially diverge from the built-ins; otherwise omit and let Copilot's defaults serve. + +**Phase 8b hook coverage list (rows where `Has fileRegex? = ✅ Yes`):** + +1. `docs-writer` — `\.(md|txt|rst|adoc)$` +2. `translate` — `(.*\.(md|ts|tsx|js|jsx)$|.*\.json$)` +3. `docs-extractor` — `\.roo/extraction/.*\.(yaml|json|md)$` +4. `architect` — `\.md$` + +Phase 8b will ship one `preToolUse` hook with a JSON policy table mapping `agentName → allowedRegex` for these four modes. + +--- + +## § 5 — Step-by-step Phase 8a execution + +Run from the active project's root in PowerShell. Assumes § 1 checklist completed. + +1. **Create the Copilot directory layout.** + + ```powershell + New-Item -ItemType Directory -Path .github\agents -Force | Out-Null + New-Item -ItemType Directory -Path .github\instructions -Force | Out-Null + New-Item -ItemType Directory -Path .github\prompts -Force | Out-Null + New-Item -ItemType Directory -Path .vscode -Force | Out-Null + ``` + +2. **Author one `.agent.md` per vault mode.** Sketch (PowerShell loop pattern — adapt the field-mapping logic from § 2.2): + + ```powershell + # Pseudocode — concrete YAML→Markdown converter is a Phase 8b deliverable + $vaultModes = "C:\git\roo-vault\global-settings\custom_modes.yaml" + $modes = ConvertFrom-Yaml (Get-Content $vaultModes -Raw) # requires powershell-yaml module + foreach ($m in $modes.customModes) { + $target = ".github\agents\$($m.slug).agent.md" + # Build frontmatter from $m.name / description / groups / allowedMcpServers (see § 2.2 mapping) + # Append $m.roleDefinition + $m.customInstructions to body + # If groups contains a fileRegex tuple, add the prose-enforcement paragraph + Set-Content -Path $target -Value $frontmatter + "`n" + $body -Encoding UTF8 + } + ``` + + **Manual fallback** (no YAML module): copy § 2.2's worked architect example, edit per row in § 4, save to `.github/agents/.agent.md`. + +3. **Copy or create `AGENTS.md`.** + + ```powershell + if (Test-Path "C:\git\Roo-Code\AGENTS.md") { + Copy-Item "C:\git\Roo-Code\AGENTS.md" .\AGENTS.md + } else { + Set-Content .\AGENTS.md @" + # AGENTS.md + Project: $((Get-Item .).Name) + ## Commands + - Test: + ## Conventions + - + "@ + } + ``` + +4. **Convert `.roo/rules/*.md` → `.github/instructions/*.instructions.md`** (script in § 2.3). + +5. **Convert `.roo/mcp.json` → `.vscode/mcp.json`.** Manual edit using the side-by-side mapping in § 3.1: rename top-level key `mcpServers` → `servers`; replace each inline secret value with `${input:}` and add a corresponding `inputs:` entry. Commit. + +6. **Convert global `mcp_settings.json` → `%APPDATA%\Code\User\mcp.json`** (or per-profile path). Use the worked target in § 3.2 verbatim, plug in the four enabled vault servers. Run **MCP: Open User Configuration** in VS Code first to confirm the actual path for your active profile. + +7. **Reload VS Code.** `Ctrl+Shift+P` → **Developer: Reload Window**. Verify: + - `.agent.md` files appear in the agents dropdown next to the chat input. + - `Chat: Configure Custom Agents` (`/agents`) lists every vault mode. + - `MCP: List Servers` shows all 4 enabled servers. + +8. **Trigger first MCP run.** In Chat, ask the architect agent to "list the open issues in this repo using the github MCP server". Verify: + - VS Code shows a `${input:githubToken}` Quick Pick on first run. + - The supplied value persists across reloads (stored in Windows Credential Manager). + - Run **MCP: Reset Trust** to confirm the prompt re-fires when secrets are cleared. + +--- + +## § 6 — Hand-off to Phase 8b + +Phase 8b inherits the following inputs from 8a: + +- **§ 4 hook coverage list** (4 modes with `fileRegex`: `docs-writer`, `translate`, `docs-extractor`, `architect`) — owns the `preToolUse` hook policy table. +- **Q-050 canonical-source decision** — recommendation in § 1 step 2 is *Chat-as-truth + `jq` generator → CLI*; Phase 8b documents the converter script and commit-time invocation. +- **Q-047 audit results** (pending user execution of § 1 step 1) — finalises the `Has fileRegex?` column in § 4. +- **Q-051 `AGENTS.local.md` dual-surface verification** (pending user execution of the test in § 2.1). + +Phase 8b deliverables (sections § 7–§ 12 + Appendix B): + +- § 7: CLI-side configuration (`~/.copilot/agents/`, `~/.copilot/instructions/`, `mcp-config.json` with `mcpServers:` schema, `COPILOT_HOME` env var). +- § 8: `preToolUse` hook reference implementation (PowerShell + JSON policy table) covering the four hook-required modes. +- § 9: MCP canonical-source generator script (per Q-050 decision). +- § 10: Automation recipes (pre-commit hooks, GitHub Actions, cron / Windows Task Scheduler). +- § 11: Validation matrix — one row per vault capability, expected behaviour on Chat / CLI / both. +- § 12: Rollback plan — revert to Roo within 5 minutes; preserve state for 30-day fallback. +- Appendix B: Path B (CLI-only) deltas for users who later prefer terminal-first workflows. + +--- + +## § 7 — CLI-side Configuration (Phase 8b-i) + +Mirrors § 3 (Chat) for the Copilot CLI surface. All paths assume Windows 11 + `COPILOT_HOME` redirected to the vault (see § 7.4). Source of record for every claim: [`50-copilot-cli-research.md`](50-copilot-cli-research.md) §§ 2, 4, 5, 9 (Q-008 / Q-031 / Q-033 resolved). + +### § 7.1 — Directory layout under `~/.copilot/` (or `$COPILOT_HOME`) + +```text +%USERPROFILE%\.copilot\ ← or $env:COPILOT_HOME if set +├── settings.json ← user-global settings (cascades over .github/copilot/settings.json) +├── copilot-instructions.md ← always-on global instructions (analogue of ~/.roo/rules/global.md) +├── instructions\ ← *.instructions.md modular instructions, applyTo: glob honoured +│ └── *.instructions.md +├── agents\ ← user-scope custom agents (CLI flavour .agent.md) +│ └── .agent.md +├── mcp-config.json ← user-scope MCP servers (mcpServers: schema, ${VAR} env vars) +├── hooks.json ← user-scope hooks (see § 8.5) +├── state\ ← vault-authored sidecar state (active-agent.txt — see § 8.3) +├── skills\ ← (out of scope for 8b-i — defer per Phase 8b-ii) +└── session-state\ ← per-session events; auto-managed +``` + +Discovery & precedence (per [50 § 5.1](50-copilot-cli-research.md#5-custom-agents---agent-agentmd) and [50 § 4.1](50-copilot-cli-research.md#4-custom-instructions)): **project (`.github/agents/`, `.github/instructions/`, `.github/mcp.json`) > user (`~/.copilot/…`) > plugins**. The Phase-8a shared assets in [§ 2](#-2--shared-assets-work-in-both-chat-and-cli) live in `.github/` and are read by both surfaces; § 7 only covers the **user-scope CLI-only** layer. + +### § 7.2 — `.agent.md` schema diff: CLI vs Chat + +The CLI's `.agent.md` schema is a **strict subset** of the VS Code Chat schema documented in [§ 2.2](#-22--agentmd-schema-and-conversion). A Chat-valid `.agent.md` is also CLI-valid; extra Chat-only fields are silently ignored on the CLI side. + +| Field | Chat (§ 2.2) | CLI | Notes | +|---|---|---|---| +| `name` | ✅ | ✅ | Same. | +| `description` | ✅ optional | ✅ **required** | CLI requires it; Chat infers from filename if missing. | +| `model` | ✅ array (priority order) | ✅ scalar | CLI accepts a single model string; arrays are not honoured. Pick the first Chat preference. | +| `tools` | ✅ | ✅ | Same allowlist syntax including `/*` wildcards. | +| `mcp-servers` | ✅ object (inline MCP defs) | ✅ array (allowlist) **or** object (inline) | CLI extension over Chat: can inline a `mcpServers:` map scoped to the agent only ([50 § 9.4](50-copilot-cli-research.md#94-per-agent-mcp-filtering)). | +| `agents` | ✅ subagent allowlist | ❌ ignored | CLI has no subagent allowlist field; sub-agent dispatch goes through the `task` tool subject to `tools:` permission. | +| `handoffs` | ✅ post-response buttons | ❌ ignored | Chat-only UI affordance. | +| `target` | ✅ `vscode \| github-copilot` | ❌ ignored | Chat-only. | +| `argument-hint` | ✅ | ❌ ignored | Chat-only. | +| `user-invocable` / `disable-model-invocation` | ✅ | ❌ ignored | Chat-only. | +| `hooks` | ✅ (Preview) | ❌ ignored | CLI hooks live in `~/.copilot/hooks.json` or `.github/hooks/*.json`, NOT in agent frontmatter (§ 8). | +| `infer` | — | ✅ optional | CLI legacy field, replaced by `user-invocable` semantics in Chat. | + +**Practical consequence:** **author one `.agent.md` per mode, commit it to `.github/agents/`, and let both surfaces consume it.** Only the user-scope agents (vault `global-settings/agents/`) need symlinking into `~/.copilot/agents/` (CLI) and `%APPDATA%\Code\User\prompts\` (Chat) — see § 2.2's user-scope sharing pattern. + +### § 7.3 — `~/.copilot/instructions/` and AGENTS.md inheritance + +Per [50 § 4.1](50-copilot-cli-research.md#4-custom-instructions) the CLI loads instructions from **all** of these locations and **concatenates** them (no priority fallback — every match is included): + +| Layer | Path | Always-on? | +|---|---|---| +| User-global, primary | `~/.copilot/copilot-instructions.md` | ✅ every session | +| User-global, modular | `~/.copilot/instructions/*.instructions.md` | Filtered by `applyTo:` glob in frontmatter; `applyTo: "**"` = always | +| Repository, primary | `.github/copilot-instructions.md` | ✅ every session in repo | +| Repository, modular | `.github/instructions/**/*.instructions.md` | Same `applyTo:` semantics | +| Cross-tool (workspace root) | `AGENTS.md` (+ `Copilot.md`, `GEMINI.md`, `CODEX.md`, `CLAUDE.md` if present) | ✅ every session | + +**AGENTS.md inheritance semantics (CLI):** the CLI honours the same nested-`AGENTS.md` cascade as Chat — the **nearest `AGENTS.md` walking up from `cwd`** wins for that subtree, but ancestors also concatenate (per [40 § 4](40-copilot-chat-research.md#custom-instructions-githubcopilot-instructionsmd) for Chat; CLI matches per [50 § 4.1](50-copilot-cli-research.md#4-custom-instructions)). Net behaviour identical between surfaces — author once, both surfaces read it. + +**Vault migration:** symlink `~/.copilot/copilot-instructions.md` → `/global-settings/copilot-instructions.md`, and symlink `~/.copilot/instructions/` → `/global-settings/instructions/`. The actual symlink scripts ship in Phase 8b-ii (out of scope here); for Phase 8b-i users can run the helper inline: + +```powershell +$vault = "C:\git\roo-vault\global-settings" +$cli = Join-Path $env:USERPROFILE ".copilot" +New-Item -ItemType Directory -Path $cli -Force | Out-Null +New-Item -ItemType SymbolicLink -Path "$cli\copilot-instructions.md" ` + -Target "$vault\copilot-instructions.md" -Force +New-Item -ItemType SymbolicLink -Path "$cli\instructions" ` + -Target "$vault\instructions" -Force +``` + +### § 7.4 — `COPILOT_HOME` env var for vault portability (resolves Q-008) + +`COPILOT_HOME` redirects **every** CLI config sub-path (settings, agents, skills, instructions, hooks, MCP, sessions) to a single root — see [50 § 2.1](50-copilot-cli-research.md#21-path-layout). This is the cleanest vault-portability hook; it eliminates the per-profile-id symlink dance that the Chat side requires (Q-026). + +**Recommended Windows 11 setup** (set once, persists across reboots and shells): + +```powershell +# Point CLI at the vault's copilot-home directory. +$copilotHome = "C:\git\roo-vault\copilot-home" +New-Item -ItemType Directory -Path $copilotHome -Force | Out-Null + +# Persist as a User-scope env var (no reboot needed; new shells inherit it). +[Environment]::SetEnvironmentVariable("COPILOT_HOME", $copilotHome, "User") + +# For the current shell session: +$env:COPILOT_HOME = $copilotHome + +# Verify: +copilot --help | Select-String -Pattern "config" -Context 0,2 +``` + +Vault layout to match: + +```text +C:\git\roo-vault\copilot-home\ +├── settings.json +├── copilot-instructions.md +├── instructions\ +├── agents\ +├── mcp-config.json ← generated by § 9 script (NOT hand-edited) +├── hooks.json ← § 8.5 reference impl +└── state\ + └── active-agent.txt ← § 8.3 sidecar (written by subagentStart hook) +``` + +**Per-invocation override** (useful in CI / multi-vault scenarios): + +```powershell +copilot --config-dir "C:\git\roo-vault-experimental\copilot-home" --agent architect "review this PR" +``` + +### § 7.5 — BYOK via `COPILOT_PROVIDER_*` env vars (resolves G-13 on CLI) + +Per [50 § 7.2 / G-13 resolution](50-copilot-cli-research.md#13-limits--known-gaps-relative-to-roo-cli-gap-catalog--phase-5b-ii-b-2) the CLI honours four env vars for bring-your-own-key: + +| Env var | Purpose | Example | +|---|---|---| +| `COPILOT_PROVIDER_TYPE` | `openai` (default) \| `azure` \| `anthropic` | `openai` | +| `COPILOT_PROVIDER_BASE_URL` | OpenAI-compatible endpoint URL | `http://localhost:11434/v1` (Ollama) | +| `COPILOT_PROVIDER_API_KEY` | Provider API key (sent as `Authorization: Bearer …`) | `sk-…` or `ollama` (any non-empty) | +| `COPILOT_MODEL` | Model name (must be set explicitly when BYOK is in use) | `llama3.1:70b` | + +**Tier requirement:** Pro+ or higher (per § 1 step 3). Free / Pro tiers ignore these env vars and fall back to GitHub-hosted models. + +**Worked example — Ollama on localhost:** + +```powershell +[Environment]::SetEnvironmentVariable("COPILOT_PROVIDER_TYPE", "openai", "User") +[Environment]::SetEnvironmentVariable("COPILOT_PROVIDER_BASE_URL", "http://localhost:11434/v1", "User") +[Environment]::SetEnvironmentVariable("COPILOT_PROVIDER_API_KEY", "ollama", "User") +[Environment]::SetEnvironmentVariable("COPILOT_MODEL", "llama3.1:70b", "User") +# Restart shell, then: +copilot -p "summarise CHANGELOG.md" -s --no-ask-user +``` + +To **revert to GitHub-hosted models for one invocation**, unset for the call: + +```powershell +$env:COPILOT_PROVIDER_BASE_URL = $null +copilot --model gpt-5 -p "…" +``` + +> ⚠️ **Chat surface still 🟠** — BYOK does NOT carry over to VS Code Copilot Chat (G-13 stays open there). Hybrid users who depend on local models must accept that interactive IDE work uses GitHub-hosted models while CLI/automation work can use BYOK. + +### § 7.6 — `~/.copilot/mcp-config.json` (`mcpServers:` schema) + +Schema fork from Chat's `.vscode/mcp.json` (see [50 § 9.2 side-by-side](50-copilot-cli-research.md#92-schema-vs-copilot-chats-vscodemcpjson--side-by-side); CG-3): + +| Axis | CLI `mcp-config.json` | Chat `.vscode/mcp.json` | +|---|---|---| +| Top-level key | **`mcpServers`** (object map) | `servers` (object map) + `inputs` array | +| Secret substitution | **`${VAR}`** / `$VAR` / `${VAR:-default}` from process env | `${input:id}` → first-run prompt → Windows Credential Manager | +| Per-server tool filter | `tools: ["*"]` or `["tool_a", …]` (required) | n/a (filtering via `.agent.md` `tools:` only) | + +**Hand-authored CLI MCP config is discouraged for Path Hybrid** — § 9 ships a generator that derives this file from `.vscode/mcp.json`. The skeleton below is shown for reference / validation only: + +```jsonc +// %USERPROFILE%\.copilot\mcp-config.json (or $env:COPILOT_HOME\mcp-config.json) +{ + "mcpServers": { + "github": { + "type": "local", + "command": "docker", + "args": ["run", "-i", "--rm", "-e", "GITHUB_PERSONAL_ACCESS_TOKEN", "ghcr.io/github/github-mcp-server"], + "env": { "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_PAT}" }, + "tools": ["*"] + }, + "context7": { + "type": "http", + "url": "https://mcp.context7.com/mcp", + "headers": { "CONTEXT7_API_KEY": "${CONTEXT7_API_KEY}" }, + "tools": ["*"] + } + } +} +``` + +Secrets must already exist in the User-scope process environment (per [50 § 9.3](50-copilot-cli-research.md#93-auth--secrets-on-windows--resolves-q-033) — the OS keychain is reserved for the GitHub auth token, not for MCP secrets): + +```powershell +[Environment]::SetEnvironmentVariable("GITHUB_PAT", "ghp_…", "User") +[Environment]::SetEnvironmentVariable("CONTEXT7_API_KEY", "c7_…", "User") +# … repeat for each MCP-server secret (see § 9 mapping table) +``` + +### § 7.7 — Worked example: `architect` mode → CLI `.agent.md` + +Same source row as [§ 2.2](#-22--agentmd-schema-and-conversion); shows the **CLI subset rendering**. In practice the Phase-8a Chat file at `.github/agents/architect.agent.md` is **already CLI-valid** because the CLI ignores Chat-only fields (§ 7.2). This section shows what a **CLI-only minimal** authoring would look like, in case a user prefers to keep Chat and CLI agent files separate. + +**Source (Roo)** — `roo-vault/global-settings/custom_modes.yaml` entry #18 (see [§ 2.2](#-22--agentmd-schema-and-conversion) for the full YAML). + +**Target (CLI-only)** — `~/.copilot/agents/architect.agent.md` (or `$env:COPILOT_HOME\agents\architect.agent.md`): + +```markdown +--- +name: architect +description: Plan, design, or strategize before implementation. Gathers context and produces a detailed plan for review. +model: claude-opus-4.7 +tools: + - view + - glob + - grep + - read + - edit # ⚠ G-1: fileRegex \.md$ enforced via § 8 preToolUse hook (CG-11 sub-agent caveat) + - create + - apply_patch + - "git/*" # MCP allowlist from Roo allowedMcpServers + - "context7/*" + - "tavily/*" + - "ado/*" +mcp-servers: + - git + - context7 + - tavily + - ado +--- + +You are Roo, an experienced technical leader who is inquisitive and an excellent planner. +Your goal is to gather information and get context to create a detailed plan for accomplishing +the user's task, which the user will review and approve before they switch into another mode +to implement the solution. + +## File-edit policy + +You may **only edit Markdown files** (matching glob `**/*.md`). The CLI enforces this +structurally via the `~/.copilot/hooks.json` preToolUse policy (see § 8) — your +`edit` / `create` / `apply_patch` calls on non-Markdown paths will be denied at runtime +with a structured error. Refuse pre-emptively rather than triggering the hook. + +> ⚠️ **Sub-agent caveat (CG-11 / [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392))**: when this agent is dispatched via the `task` tool from another agent, the preToolUse hook is bypassed. +> Until upstream fixes the bug, **do not delegate restricted file work to sub-agents** — +> run architect via `copilot --agent architect` directly. + +## Shared instructions + +See `.github/instructions/architect-shared.instructions.md` (cross-tool body migrated +from `roo-vault/shared-modes/architect.md`). +``` + +**Roo → CLI `.agent.md` field mapping** (deltas vs the Chat mapping table in [§ 2.2](#-22--agentmd-schema-and-conversion)): + +| Roo field | CLI `.agent.md` target | Notes | +|---|---|---| +| `groups: [read]` | `tools: [view, glob, grep, read]` | CLI tool names (per [50 § 3.6](50-copilot-cli-research.md#36-built-in-tool-surface)). | +| `groups: [edit]` | `tools: [edit, create, apply_patch]` | CLI splits write into 3 tools. | +| `groups: [command]` | `tools: [bash, powershell]` (or specific subfamily) | OS-specific; on Windows usually only `powershell*`. | +| `groups: [browser]` | `tools: [web_fetch]` | Closest CLI analogue. | +| `groups: [mcp]` + `allowedMcpServers: [...]` | `tools: ["/*"]` + `mcp-servers: [...]` | Both fields set; `mcp-servers:` is the CLI-only allowlist. | + +--- + +## § 8 — `preToolUse` Hook for `fileRegex` Enforcement (Phase 8b-i) + +Implements the structural enforcement promised in [§ 2.2](#-22--agentmd-schema-and-conversion) and [§ 4](#-4--17-mode-mapping-table) for the **4 vault modes that have `fileRegex` restrictions**. This section is the canonical CLI-side mitigation for G-1 (per [50 § 10.4 / 10.6](50-copilot-cli-research.md#104-pretooluse-deep-dive--the-fileregex-substitute)). + +### § 8.1 — Hook coverage list (the 4 modes) + +| Mode | Roo `fileRegex` | CLI policy regex (PowerShell-escaped) | +|---|---|---| +| `docs-writer` | `\.(md\|txt\|rst\|adoc)$` | `'\.(md\|txt\|rst\|adoc)$'` | +| `translate` | `(.*\.(md\|ts\|tsx\|js\|jsx)$\|.*\.json$)` | `'\.(md\|ts\|tsx\|js\|jsx\|json)$'` (simplified equivalent) | +| `docs-extractor` | `\.roo/extraction/.*\.(yaml\|json\|md)$` | `'[\\/]\.roo[\\/]extraction[\\/].*\.(ya?ml\|json\|md)$'` | +| `architect` | `\.md$` | `'\.md$'` | + +These four — and only these four — produce the `~/.copilot/state/mode-policies.json` table in § 8.2. All other vault modes carry no `fileRegex` and therefore need no hook coverage (see [§ 4](#-4--17-mode-mapping-table) `Has fileRegex?` column). + +### § 8.2 — JSON policy table — `~/.copilot/state/mode-policies.json` + +The hook reads its policy from a separate JSON file so the regex can be edited without touching the script. Authored once in the vault, symlinked into `$COPILOT_HOME/state/`. + +```jsonc +// %COPILOT_HOME%\state\mode-policies.json +// (vault canonical: roo-vault\copilot-home\state\mode-policies.json) +{ + "version": 1, + "policies": { + "docs-writer": { "tools": ["edit", "create", "apply_patch"], "pathRegex": "\\.(md|txt|rst|adoc)$" }, + "translate": { "tools": ["edit", "create", "apply_patch"], "pathRegex": "\\.(md|ts|tsx|js|jsx|json)$" }, + "docs-extractor": { "tools": ["edit", "create", "apply_patch"], "pathRegex": "[\\\\/]\\.roo[\\\\/]extraction[\\\\/].*\\.(ya?ml|json|md)$" }, + "architect": { "tools": ["edit", "create", "apply_patch"], "pathRegex": "\\.md$" } + } +} +``` + +JSON regex strings use **double-escaped backslashes** (`\\` in JSON = `\` in PowerShell regex). Test a regex in PowerShell before committing: `'foo.md' -match '\.md$'` should return `True`. + +### § 8.3 — Active-agent discovery (CG-13 mitigation) + +Per [50 § 10.4 / Q-037](50-copilot-cli-research.md#104-pretooluse-deep-dive--the-fileregex-substitute) the `preToolUse` payload does **not** include the active agent name. The hook reads it from a sidecar file at `$COPILOT_HOME/state/active-agent.txt` written by a `sessionStart` hook (and refreshed by `subagentStart` when sub-agents are in use). Single-line plain text containing the agent slug: + +```text +architect +``` + +Two write paths supported — the cleaner one is a wrapper, the more portable one is a hook: + +**Option A — wrapper script** (recommended for vault use): + +```powershell +# %COPILOT_HOME%\bin\copilot-with-agent.ps1 +param([Parameter(Mandatory)][string]$Agent, [Parameter(ValueFromRemainingArguments)]$Args) +$state = Join-Path $env:COPILOT_HOME 'state' +New-Item -ItemType Directory -Path $state -Force | Out-Null +Set-Content -Path (Join-Path $state 'active-agent.txt') -Value $Agent -NoNewline -Encoding UTF8 +& copilot --agent $Agent @Args +``` + +Invoke as `pwsh -File %COPILOT_HOME%\bin\copilot-with-agent.ps1 -Agent architect "plan the migration"`. + +**Option B — `sessionStart` hook** (ships zero-touch but cannot read the `--agent` flag from `argv`; user must `/agent ` once at the start of the session for the file to update): + +```powershell +# Snippet inside enforce-file-regex.ps1 (also wired to sessionStart event) +$active = $env:COPILOT_AGENT # ⚠ uncertain — see Q-054 +if ($active) { + Set-Content -Path (Join-Path $env:COPILOT_HOME 'state\active-agent.txt') ` + -Value $active -NoNewline -Encoding UTF8 +} +``` + +⚠ Whether the CLI exports `$env:COPILOT_AGENT` (or any env var carrying the active agent name) to spawned hook processes is not yet confirmed — see new **Q-054**. Until confirmed, Option A is the reliable path. + +### § 8.4 — Reference implementation: `enforce-file-regex.ps1` + +Refined from [50 § 10.4](50-copilot-cli-research.md#104-pretooluse-deep-dive--the-fileregex-substitute). Reads the policy table from § 8.2 instead of inlining the regex map. + +```powershell +# %COPILOT_HOME%\hooks\enforce-file-regex.ps1 +# Wired to preToolUse via ~/.copilot/hooks.json (§ 8.5). +# Exit 0 always — verdict is delivered via JSON to stdout. +$ErrorActionPreference = 'Stop' + +try { + # 1. Read the JSON payload from stdin (CLI feeds it here per hooks-configuration ref). + $inputObj = [Console]::In.ReadToEnd() | ConvertFrom-Json + $toolName = $inputObj.toolName + + # 2. Load the policy table (cached optimisation possible later — keep simple for now). + $policyPath = Join-Path $env:COPILOT_HOME 'state\mode-policies.json' + if (-not (Test-Path $policyPath)) { exit 0 } # no policies → allow + $policyDoc = Get-Content $policyPath -Raw | ConvertFrom-Json + + # 3. Determine active agent from sidecar (§ 8.3). + $stateFile = Join-Path $env:COPILOT_HOME 'state\active-agent.txt' + if (-not (Test-Path $stateFile)) { exit 0 } + $agent = (Get-Content $stateFile -Raw).Trim() + if (-not $agent) { exit 0 } + + # 4. Look up policy for this agent. No policy → allow. + $policy = $policyDoc.policies.$agent + if (-not $policy) { exit 0 } + + # 5. Only enforce on the tools the policy names. + if ($policy.tools -notcontains $toolName) { exit 0 } + + # 6. Parse toolArgs (it's a JSON STRING, not an object — must parse twice). + $toolArgs = $null + try { $toolArgs = $inputObj.toolArgs | ConvertFrom-Json } catch { exit 0 } + $path = $toolArgs.path + if (-not $path) { exit 0 } + + # 7. Match against policy regex; deny if it doesn't match. + if ($path -notmatch $policy.pathRegex) { + @{ + permissionDecision = 'deny' + permissionDecisionReason = "Agent '$agent' may only $toolName files matching /$($policy.pathRegex)/. Refusing to modify '$path'." + } | ConvertTo-Json -Compress + exit 0 + } + exit 0 # explicit allow +} +catch { + # Hook failures are logged and treated as allow per CLI hook contract. + # Print error to stderr for diagnostics; do not block. + [Console]::Error.WriteLine("enforce-file-regex.ps1 error: $_") + exit 0 +} +``` + +### § 8.5 — `~/.copilot/hooks.json` registration + +Wires the script to the `preToolUse` event. Single user-scope file (per [50 § 10.1](50-copilot-cli-research.md#101-storage-paths--precedence)): + +```jsonc +// %COPILOT_HOME%\hooks.json (vault canonical: roo-vault\copilot-home\hooks.json) +{ + "version": 1, + "hooks": { + "preToolUse": [ + { + "type": "command", + "powershell": "pwsh -NoProfile -ExecutionPolicy Bypass -File ${env:COPILOT_HOME}\\hooks\\enforce-file-regex.ps1", + "bash": "${COPILOT_HOME}/hooks/enforce-file-regex.sh", + "timeoutSec": 5 + } + ] + } +} +``` + +A POSIX `enforce-file-regex.sh` is shipped alongside for cross-platform parity (out of scope for 8b-i — Windows-first per the brief). + +### § 8.6 — Caveats & known limitations + +**🚨 CG-11 — sub-agent invocations bypass `preToolUse` ([`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392)).** When an agent dispatches a sub-agent via the `task` tool, the sub-agent's tool calls **do not fire `preToolUse`**. Concretely: if the orchestrator dispatches `task(agent="architect", prompt="…")`, the architect sub-agent can call `edit("foo.ts")` and the hook will not block it. + +**Mitigation for Phase 8b-i (until upstream fix lands):** + +1. **Avoid sub-agent delegation for the 4 restricted modes.** Run `docs-writer`, `translate`, `docs-extractor`, and `architect` only via top-level `--agent ` boot, not via `task` dispatch. +2. **Document the constraint in each restricted agent's body** (§ 7.7 example shows the warning paragraph) — the agent itself must refuse `task` invocation. +3. **Optional:** the orchestrator agent's body should explicitly forbid delegating restricted work: *"Never dispatch architect/docs-writer/translate/docs-extractor as sub-agents — request the user switch agents instead."* +4. **Track [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392)** in § 1 step 7's pinned-issue list; on resolution, drop this caveat. + +**Other inherited caveats** (do not block 8b-i but are acceptance conditions): + +- **Parallel-call race** ([`copilot-cli#2893`](https://github.com/github/copilot-cli/issues/2893)) — keep the script under ~50 ms work; current impl with file I/O ≈ 100–300 ms. Empirical measurement still owed (Q-039). +- **`modifiedArgs` not honoured** ([`copilot-cli#2013`](https://github.com/github/copilot-cli/issues/2013)) — only allow / deny is supported; the hook cannot rewrite the proposed write path. +- **Plugin-defined hooks don't fire** ([`copilot-cli#2540`](https://github.com/github/copilot-cli/issues/2540)) — ship the policy as a user or repo hook, never as a plugin. + + + +--- + +## § 9 — MCP Canonical-Source Generator (Phase 8b-i, resolves Q-050) + +Per the Q-050 decision recorded in § 1 step 2 and reaffirmed in [§ 90 decision log entry below](90-decision-log.md): **Chat's `.vscode/mcp.json` is the source of truth**. The CLI's `mcp-config.json` (or `.github/mcp.json` for project-scope) is **generated** on demand. Edits go in the Chat file; the CLI file is treated as build output. + +### § 9.1 — Generator script — `scripts/generate-cli-mcp.ps1` + +```powershell +# scripts/generate-cli-mcp.ps1 +# Generate Copilot CLI mcp-config.json from Copilot Chat .vscode/mcp.json. +# Source of truth: Chat (.vscode/mcp.json). Output: $env:COPILOT_HOME\mcp-config.json +# (or ~/.copilot/mcp-config.json if COPILOT_HOME is unset). +# +# Q-050 (resolved): Chat-as-truth + generator → CLI. + +[CmdletBinding()] +param( + [string]$ChatConfig = '.vscode\mcp.json', + [string]$CliConfig = $(if ($env:COPILOT_HOME) { Join-Path $env:COPILOT_HOME 'mcp-config.json' } + else { Join-Path $env:USERPROFILE '.copilot\mcp-config.json' }), + [switch]$DryRun +) + +# Mapping: Chat ${input:id} → CLI ${ENV_VAR_NAME} +# Add entries here when new MCP servers are introduced; one row per Chat input id. +$envVarMap = @{ + 'githubToken' = 'GITHUB_PAT' + 'tavilyKey' = 'TAVILY_API_KEY' + 'context7Key' = 'CONTEXT7_API_KEY' + 'adoPat' = 'ADO_PAT' + 'braveKey' = 'BRAVE_API_KEY' + # microsoft-learn has no auth → no entry + # memory / filesystem have no secrets → no entry +} + +if (-not (Test-Path $ChatConfig)) { + throw "Chat MCP config not found at $ChatConfig" +} + +$chatRaw = Get-Content $ChatConfig -Raw +$chatJson = $chatRaw | ConvertFrom-Json + +if (-not $chatJson.servers) { + throw "Chat MCP config has no top-level 'servers' key — is this really a .vscode/mcp.json file?" +} + +# 1. Build the mcpServers map from Chat's servers map. +$mcpServers = [ordered]@{} +foreach ($name in $chatJson.servers.PSObject.Properties.Name) { + $serverDef = $chatJson.servers.$name + # Round-trip through JSON to get a deep clone (PowerShell ConvertFrom-Json gives PSCustomObjects). + $cliServer = $serverDef | ConvertTo-Json -Depth 20 | ConvertFrom-Json + # Default tools allowlist on the CLI side. + if (-not $cliServer.PSObject.Properties.Name -contains 'tools') { + $cliServer | Add-Member -NotePropertyName 'tools' -NotePropertyValue @('*') + } + $mcpServers[$name] = $cliServer +} + +# 2. Rewrite ${input:id} → ${ENV_VAR_NAME} recursively (env, headers, args, url). +function Rewrite-Inputs { + param($node) + if ($null -eq $node) { return $node } + if ($node -is [string]) { + return ([regex]'\$\{input:([^}]+)\}').Replace($node, { + param($m) + $id = $m.Groups[1].Value + if ($envVarMap.ContainsKey($id)) { + return '${' + $envVarMap[$id] + '}' + } else { + Write-Warning "No env-var mapping for Chat input id '$id'. Leaving placeholder unchanged." + return $m.Value + } + }) + } + if ($node -is [System.Collections.IEnumerable] -and $node -isnot [string]) { + return @($node | ForEach-Object { Rewrite-Inputs $_ }) + } + if ($node -is [psobject]) { + foreach ($prop in @($node.PSObject.Properties)) { + $node.$($prop.Name) = Rewrite-Inputs $prop.Value + } + return $node + } + return $node +} + +foreach ($name in $mcpServers.Keys) { + $mcpServers[$name] = Rewrite-Inputs $mcpServers[$name] +} + +# 3. Emit. +$outDoc = [ordered]@{ mcpServers = $mcpServers } +$outJson = $outDoc | ConvertTo-Json -Depth 20 + +if ($DryRun) { + Write-Host "--- Generated CLI mcp-config.json (dry run) ---" + Write-Host $outJson + return +} + +$outDir = Split-Path -Parent $CliConfig +New-Item -ItemType Directory -Path $outDir -Force | Out-Null +Set-Content -Path $CliConfig -Value $outJson -Encoding UTF8 +Write-Host "Wrote CLI MCP config: $CliConfig" +Write-Host "Source of truth: $ChatConfig" +Write-Host "" +Write-Host "Reminder: ensure these env vars are set in your User environment:" +$envVarMap.Values | Sort-Object -Unique | ForEach-Object { Write-Host " - $_" } +``` + +### § 9.2 — Env var mapping table for the 7 vault MCP servers + +Compiled from [20 § MCP Server Inventory](20-roo-vault-inventory.md). The Chat `${input:id}` IDs follow the convention used in [§ 3.1 / § 3.2](#-31--vscodemcpjson-workspace). + +| # | Server | Scope | Auth required? | Chat `${input:id}` | CLI env var | Notes | +|---|---|---|---|---|---|---| +| 1 | `github` | global | ✅ GitHub PAT | `githubToken` | `GITHUB_PAT` | Fine-grained PAT preferred. | +| 2 | `context7` | global | ✅ API key (header) | `context7Key` | `CONTEXT7_API_KEY` | HTTP transport. | +| 3 | `tavily` | global | ✅ API key (env) | `tavilyKey` | `TAVILY_API_KEY` | Docker stdio. | +| 4 | `microsoft-learn` | global | ❌ none | — | — | No env var needed. | +| 5 | `ado` | per-project (Roo-Code, pgsql-orion) | ✅ ADO PAT | `adoPat` | `ADO_PAT` | `npx -y @azure-devops/mcp msdata`. | +| 6 | `git` | per-project (Roo-Code) | ❌ none (Docker mount) | — | — | `${workspaceFolder}` → CLI uses `${PWD}` or absolute path. | +| 7 | `brave-search` | global (currently disabled) | ✅ API key | `braveKey` | `BRAVE_API_KEY` | Skip until enabled. | + +**Disabled-in-vault servers** (`memory`, `filesystem`, `brave-search`): omit from `.vscode/mcp.json` entirely; the generator simply won't see them. To re-enable later, add them to the Chat config and re-run § 9.3 — the generator picks them up. + +**Set the env vars once** (User scope; new shells inherit): + +```powershell +[Environment]::SetEnvironmentVariable("GITHUB_PAT", "ghp_…", "User") +[Environment]::SetEnvironmentVariable("CONTEXT7_API_KEY", "c7_…", "User") +[Environment]::SetEnvironmentVariable("TAVILY_API_KEY", "tvly-…", "User") +[Environment]::SetEnvironmentVariable("ADO_PAT", "az…", "User") +# BRAVE_API_KEY left unset until the server is re-enabled. +``` + +### § 9.3 — One-liner: regenerate after editing Chat MCP config + +```powershell +# After editing .vscode/mcp.json (or %APPDATA%\Code\User\mcp.json) in VS Code: +pwsh -File .\scripts\generate-cli-mcp.ps1 +``` + +For the user-scope Chat MCP file, point `-ChatConfig` at it explicitly: + +```powershell +pwsh -File .\scripts\generate-cli-mcp.ps1 ` + -ChatConfig "$env:APPDATA\Code\User\mcp.json" +``` + +Dry-run mode prints the generated JSON to stdout without writing: + +```powershell +pwsh -File .\scripts\generate-cli-mcp.ps1 -DryRun +``` + + + +### § 9.4 — When NOT to use the generator + +Two scenarios where the generator is bypassed: + +1. **Project-scope CLI MCP** (`.github/mcp.json`) — the generator targets the user-scope file. For per-project CLI MCP, copy the relevant servers from `.vscode/mcp.json` manually and rename `servers` → `mcpServers` (small file; one-time edit per project). +2. **CLI-only MCP servers** that have no Chat counterpart (e.g., a local-only test MCP) — author them directly in `~/.copilot/mcp-config.json` after the generator runs, OR add them to `.vscode/mcp.json` first (Chat will simply not know about them if you don't enable them in Chat) and let the generator pick them up. + +--- + +## § 10 — Setup Automation (Phase 8b-ii) + +Models the existing vault [`setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1) symlink-and-env pattern (per [20 § Global Settings](20-roo-vault-inventory.md)). Three deliverables: (1) `scripts/setup-copilot-vault.ps1` for user-scope (one-time per machine), (2) `scripts/setup-copilot-project.ps1` for per-project bootstrap, (3) a pre-commit hook stub that re-runs the § 9 generator when `.vscode/mcp.json` changes. + +**Decision recap (see [decision-log entry below](90-decision-log.md)):** **symlink, do not copy.** The vault is the single source of truth; both Chat and CLI consume it via filesystem symlinks. Copying would fork edits and defeat multi-machine portability. + +### § 10.1 — `scripts/setup-copilot-vault.ps1` (user-scope, one-time) + +Idempotent. Creates the vault layout, sets persistent User-scope env vars, and symlinks `$COPILOT_HOME` sub-paths into the vault. + +```powershell +# scripts/setup-copilot-vault.ps1 +# One-time per-machine setup for the Copilot side of Path Hybrid. +# Modeled on roo-vault\setup-vault.ps1 (per [20 § Global Settings]). +# Idempotent: safe to re-run after vault edits or on a fresh machine. +# +# Requires: Windows 11, PowerShell 5.1+ or pwsh 7+, AND either +# (a) Administrator shell, OR (b) Developer Mode enabled +# (Settings → Privacy & security → For developers → Developer Mode). +[CmdletBinding()] +param( + [string]$VaultRoot = 'C:\git\roo-vault', + [string]$CopilotHome = 'C:\git\roo-vault\copilot-home', + [switch]$SkipMcpGen, + [switch]$WhatIf +) + +$ErrorActionPreference = 'Stop' + +# ── 0. Pre-flight: symlink-capability check ────────────────────────────── +function Test-CanSymlink { + $isAdmin = ([Security.Principal.WindowsPrincipal] ` + [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole( + [Security.Principal.WindowsBuiltInRole]::Administrator) + if ($isAdmin) { return $true } + $devMode = Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\AppModelUnlock' ` + -Name 'AllowDevelopmentWithoutDevLicense' -ErrorAction SilentlyContinue + return ($devMode -and $devMode.AllowDevelopmentWithoutDevLicense -eq 1) +} +if (-not (Test-CanSymlink)) { + Write-Warning @" +Symlink creation requires either: + (a) Administrator-elevated shell, OR + (b) Developer Mode enabled (Settings -> Privacy & security -> For developers). +Re-run this script in an elevated shell or after enabling Developer Mode. +"@ + exit 1 +} + +# ── 1. Ensure vault canonical directories exist ────────────────────────── +$vaultCopilot = $CopilotHome # by convention COPILOT_HOME == vault\copilot-home +$required = @( + "$vaultCopilot", + "$vaultCopilot\agents", + "$vaultCopilot\instructions", + "$vaultCopilot\hooks", + "$vaultCopilot\state", + "$vaultCopilot\bin" +) +foreach ($d in $required) { + if (-not (Test-Path $d)) { + Write-Host " + mkdir $d" + if (-not $WhatIf) { New-Item -ItemType Directory -Path $d -Force | Out-Null } + } +} + +# ── 2. Persistent User env vars (no reboot needed) ─────────────────────── +function Set-UserEnv($name, $value, [switch]$Placeholder) { + $current = [Environment]::GetEnvironmentVariable($name, 'User') + if ($Placeholder -and $current) { + Write-Host " = $name (already set; preserving existing value)" + return + } + if ($current -eq $value) { + Write-Host " = $name (unchanged)" + return + } + Write-Host " + $name = $value" + if (-not $WhatIf) { + [Environment]::SetEnvironmentVariable($name, $value, 'User') + Set-Item -Path "env:$name" -Value $value + } +} + +Set-UserEnv 'COPILOT_HOME' $CopilotHome + +# BYOK placeholders (don't clobber if user already configured) +Set-UserEnv 'COPILOT_PROVIDER_TYPE' 'openai' -Placeholder +Set-UserEnv 'COPILOT_PROVIDER_BASE_URL' 'http://localhost:11434/v1' -Placeholder +Set-UserEnv 'COPILOT_PROVIDER_API_KEY' 'CHANGE_ME_BYOK_KEY' -Placeholder +Set-UserEnv 'COPILOT_MODEL' 'llama3.1:70b' -Placeholder + +# MCP secret placeholders (per § 9.2) +Set-UserEnv 'GITHUB_PAT' 'CHANGE_ME_GITHUB_PAT' -Placeholder +Set-UserEnv 'TAVILY_API_KEY' 'CHANGE_ME_TAVILY_KEY' -Placeholder +Set-UserEnv 'CONTEXT7_API_KEY' 'CHANGE_ME_CONTEXT7_KEY' -Placeholder +Set-UserEnv 'ADO_PAT' 'CHANGE_ME_ADO_PAT' -Placeholder + +# ── 3. Symlink CLI consumer paths to vault canonical paths ─────────────── +# CLI reads from $env:COPILOT_HOME directly when set, so the "consumer" +# location IS the vault. The links below cover the legacy ~/.copilot path +# for tools that don't honour COPILOT_HOME yet. +function New-Link($linkPath, $targetPath, [string]$kind = 'SymbolicLink') { + if (Test-Path $linkPath) { + $existing = Get-Item $linkPath -Force + if ($existing.LinkType -eq 'SymbolicLink' -and $existing.Target -contains $targetPath) { + Write-Host " = link $linkPath (already correct)" + return + } + Write-Host " ~ removing stale link/file at $linkPath" + if (-not $WhatIf) { Remove-Item $linkPath -Recurse -Force } + } + Write-Host " + link $linkPath -> $targetPath" + if (-not $WhatIf) { + New-Item -ItemType $kind -Path $linkPath -Target $targetPath -Force | Out-Null + } +} + +$legacyCli = Join-Path $env:USERPROFILE '.copilot' +if (-not (Test-Path $legacyCli)) { + New-Item -ItemType Directory -Path $legacyCli -Force | Out-Null +} +New-Link "$legacyCli\agents" "$vaultCopilot\agents" +New-Link "$legacyCli\instructions" "$vaultCopilot\instructions" +New-Link "$legacyCli\hooks.json" "$vaultCopilot\hooks.json" +New-Link "$legacyCli\state" "$vaultCopilot\state" +# mcp-config.json is GENERATED (§ 9); link points to the same vault file +# the generator writes, so the legacy CLI sees regen output instantly. +New-Link "$legacyCli\mcp-config.json" "$vaultCopilot\mcp-config.json" + +# Chat user-scope agents: per [§ 2.2 user-scope sharing pattern], symlink +# each *.agent.md individually because %APPDATA%\Code\User\prompts\ is shared +# with .prompt.md / .instructions.md / *.toolsets.jsonc. +$chatPrompts = Join-Path $env:APPDATA 'Code\User\prompts' +if (-not (Test-Path $chatPrompts)) { + New-Item -ItemType Directory -Path $chatPrompts -Force | Out-Null +} +Get-ChildItem "$vaultCopilot\agents" -Filter '*.agent.md' -ErrorAction SilentlyContinue | + ForEach-Object { New-Link "$chatPrompts\$($_.Name)" $_.FullName } + +# ── 4. Invoke MCP generator (§ 9) so mcp-config.json materializes now ─── +if (-not $SkipMcpGen) { + $gen = Join-Path $PSScriptRoot 'generate-cli-mcp.ps1' + if (Test-Path $gen) { + Write-Host " > running generate-cli-mcp.ps1" + if (-not $WhatIf) { & pwsh -NoProfile -File $gen } + } else { + Write-Warning "generate-cli-mcp.ps1 not found at $gen — skipping MCP generation." + } +} + +Write-Host "" +Write-Host "Setup complete. COPILOT_HOME = $CopilotHome" +Write-Host "Open a new shell (or VS Code window) for env vars to take effect." +Write-Host "Replace the CHANGE_ME_* env vars with real secrets via:" +Write-Host ' [Environment]::SetEnvironmentVariable("GITHUB_PAT","ghp_…","User")' +``` + +**Idempotency contract:** every mutation is preceded by an existence/equality check. Re-running the script after vault content changes only updates new/changed links; unchanged links are skipped (logged as `=`). + +### § 10.2 — `scripts/setup-copilot-project.ps1` (per-project bootstrap) + +Run once per repo that adopts Path Hybrid. Copies the shared-asset templates from the vault into the current repo (these need to be **committed**, not symlinked, because they're per-project assets that go through code review). + +```powershell +# scripts/setup-copilot-project.ps1 +# Per-project bootstrap. Run from the project root. +# Copies (not symlinks) per-project Copilot assets so they live inside the repo. +[CmdletBinding()] +param( + [string]$VaultRoot = 'C:\git\roo-vault', + [string]$ProjectRoot = (Get-Location).Path, + [switch]$Force +) +$ErrorActionPreference = 'Stop' + +$templates = Join-Path $VaultRoot 'copilot-home\project-templates' +if (-not (Test-Path $templates)) { + throw "Project-template root not found: $templates. Did you run setup-copilot-vault.ps1 and stage templates in the vault?" +} + +function Copy-IfMissing($src, $dst) { + if ((Test-Path $dst) -and -not $Force) { + Write-Host " = $dst (exists; pass -Force to overwrite)" + return + } + $dstDir = Split-Path -Parent $dst + if (-not (Test-Path $dstDir)) { New-Item -ItemType Directory -Path $dstDir -Force | Out-Null } + Copy-Item -Path $src -Destination $dst -Recurse -Force + Write-Host " + $dst" +} + +# 1. .github/agents/ (project-scope agent overrides; can be empty initially) +Copy-IfMissing "$templates\.github\agents" (Join-Path $ProjectRoot '.github\agents') + +# 2. .github/instructions/ (path-scoped instructions) +Copy-IfMissing "$templates\.github\instructions" (Join-Path $ProjectRoot '.github\instructions') + +# 3. .vscode/mcp.json (MCP source of truth — Q-050) +Copy-IfMissing "$templates\.vscode\mcp.json" (Join-Path $ProjectRoot '.vscode\mcp.json') + +# 4. AGENTS.md (only if missing — never clobber an existing one) +$agentsMd = Join-Path $ProjectRoot 'AGENTS.md' +if (-not (Test-Path $agentsMd)) { + Copy-IfMissing "$templates\AGENTS.md" $agentsMd +} + +# 5. .gitignore additions +$gitignore = Join-Path $ProjectRoot '.gitignore' +$additions = @('AGENTS.local.md', '.copilot/', 'mcp-config.json') +if (Test-Path $gitignore) { + $existing = Get-Content $gitignore + foreach ($a in $additions) { + if ($existing -notcontains $a) { + Add-Content -Path $gitignore -Value $a + Write-Host " + .gitignore += $a" + } + } +} + +# 6. Pre-commit hook stub (§ 10.3) +$hook = Join-Path $ProjectRoot '.git\hooks\pre-commit' +if (-not (Test-Path $hook)) { + Copy-IfMissing "$templates\hooks\pre-commit" $hook + if ($IsLinux -or $IsMacOS) { & chmod +x $hook } +} + +Write-Host "" +Write-Host "Project bootstrap complete for: $ProjectRoot" +Write-Host "Next: edit .vscode/mcp.json with your servers, then commit." +``` + +### § 10.3 — Pre-commit hook stub (closes § 9.3 TODO) + +Re-runs `generate-cli-mcp.ps1` whenever `.vscode/mcp.json` (or the user-scope mcp.json) changes, so the CLI mirror cannot drift from the Chat source. + +```bash +#!/usr/bin/env bash +# .git/hooks/pre-commit (also shipped at vault\copilot-home\project-templates\hooks\pre-commit) +# Regenerate $COPILOT_HOME/mcp-config.json when .vscode/mcp.json is staged. +set -e + +# Only run if the MCP source changed in this commit. +if git diff --cached --name-only | grep -qE '^\.vscode/mcp\.json$'; then + echo "[pre-commit] .vscode/mcp.json changed -> regenerating CLI mcp-config.json" + if command -v pwsh >/dev/null 2>&1; then + pwsh -NoProfile -File scripts/generate-cli-mcp.ps1 + else + powershell.exe -NoProfile -File scripts/generate-cli-mcp.ps1 + fi + # Stage the regenerated file IF it lives inside the repo (vault-link case + # writes to $COPILOT_HOME outside the repo and there's nothing to stage). + if [ -f .copilot/mcp-config.json ]; then + git add .copilot/mcp-config.json + fi +fi + +# Also re-validate hooks.json policy table (§ 8.2) hasn't drifted. +if git diff --cached --name-only | grep -qE 'mode-policies\.json$'; then + echo "[pre-commit] mode-policies.json changed -> validating JSON" + pwsh -NoProfile -Command "Get-Content '\$env:COPILOT_HOME\state\mode-policies.json' -Raw | ConvertFrom-Json | Out-Null" +fi +``` + +Install via `setup-copilot-project.ps1` (step 6 above). For PowerShell-only environments, a `pre-commit.ps1` wrapper invoked from `.git/hooks/pre-commit` is the portable form. + +--- + +## § 11 — Validation Matrix (Phase 8b-ii) + +Table-driven runbook. Every claim made in §§ 0–10 is reduced to a copy-paste test with a pass/fail criterion. **Run the entire matrix** during the Stage-1 → Stage-2 transition (per [`70 § 4.4`](70-migration-paths.md#-44--phasing-suggestion)) and re-run the **Cross-cutting** rows after any vault edit. + +**Conventions:** +- IDs prefixed `T-` for **test**; suffixed by gap/feature ID (`G-1`, `CG-11`, `W-x`, etc.) when verifying a known issue. +- `cmd`s assume PowerShell 7+ (`pwsh`) on Windows 11 with `$env:COPILOT_HOME` set per § 7.4. +- "Pass" means the *expected output* OR functionally-equivalent output is observed. Fail = block Stage-2 cutover. +- Closes the `` from [§ 8.6](#-86--caveats--known-limitations). + +### § 11.1 — Chat-side tests (8 rows) + +| ID | Claim | Test command | Expected | Pass criteria | +|---|---|---|---|---| +| **T-CHAT-01** | Custom agent loads from `.github/agents/` ([§ 3](#-3--chat-side-configuration)) | In VS Code → reload window → open Chat → click agent dropdown next to input | All vault `.agent.md` files appear by `name:` (e.g., `🏗️ Architect`) | All 17 modes listed; none missing | +| **T-CHAT-02 (G-1)** | `fileRegex` is **NOT** enforced on Chat (known limitation) | Switch to `🏗️ Architect`; ask: *"Edit `package.json` and add a `"foo": "bar"` entry."* | Agent attempts the edit (proves G-1) **OR** prose-refuses citing § 2.2 worked example | If edit proceeds: G-1 confirmed unenforced — **document the workaround** (use CLI for restricted modes per § 8.6). If prose-refuses: prose guard works; structural enforcement still missing. | +| **T-CHAT-03** | All 4 enabled MCP servers reachable | In Chat: `MCP: List Servers` | `github`, `context7`, `tavily`, `microsoft-learn` all show ✅ Started | All 4 green | +| **T-CHAT-04** | `${input:githubToken}` first-run prompt fires | `MCP: Reset Trust` → ask agent *"List open issues in this repo"* | VS Code Quick Pick prompts for GitHub PAT; value persists to Windows Credential Manager | Prompt appears once; subsequent calls silent | +| **T-CHAT-05** | Prompt files invokable via slash | Type `/` in chat input | `.github/prompts/*.prompt.md` files appear in slash menu | At least one prompt invokable; output matches body | +| **T-CHAT-06** | `AGENTS.md` is picked up | Ask any agent: *"Quote the first heading from AGENTS.md verbatim."* | Agent quotes the project's `AGENTS.md` header | Quote matches file | +| **T-CHAT-07 (Q-051)** | `AGENTS.local.md` overlay (token-quote test from § 2.1) | Author `AGENTS.local.md` with `LOCAL-OVERRIDE-12345`; ask *"Quote any line containing LOCAL-OVERRIDE."* | Agent quotes the token | If quoted → Q-051 resolved positive; if not → use user-scope fallback per § 2.1 | +| **T-CHAT-08** | Per-server tool wildcard works | Switch to `architect`; ask *"Use the github MCP to fetch issue #1."* | `github/get_issue` succeeds; `tavily/*` tools rejected (not in architect's `tools:`) | Allowlist enforced | + +### § 11.2 — CLI-side tests, including 8 hook policy tests (12 rows) + +The 8 hook tests are the heart of this section — one **positive** (path matches policy → allowed) and one **negative** (path violates policy → denied) per restricted mode. Closes the § 8.6 TODO. + +| ID | Mode / Claim | Test command | Expected output | Pass criteria | +|---|---|---|---|---| +| **T-CLI-01** | CLI agent loads | `copilot --list-agents` (or `copilot /agents` interactively) | All vault agents listed by slug | All 17 modes appear | +| **T-CLI-02 (CG-3)** | MCP via `mcpServers:` schema works | `copilot -p "use the github MCP to list open issues" --agent code` | Returns issue list from GitHub MCP | Non-empty result; no schema-error in stderr | +| **T-CLI-03 (G-13)** | BYOK via `COPILOT_PROVIDER_*` (Pro+ only) | Set `COPILOT_PROVIDER_BASE_URL=http://localhost:11434/v1`; `copilot -p "say hi" --no-ask-user` | Response from local Ollama model | Pro+ tier required; Free tier silently falls back (mark N/A) | +| **T-HOOK-01a (architect ✅)** | architect editing `.md` is **allowed** | `pwsh $env:COPILOT_HOME\bin\copilot-with-agent.ps1 -Agent architect "create a file foo.md with hello"` | File `foo.md` created | Hook log shows allow; file exists | +| **T-HOOK-01b (architect ❌)** | architect editing `.ts` is **denied** | `pwsh $env:COPILOT_HOME\bin\copilot-with-agent.ps1 -Agent architect "create a file foo.ts with hello"` | Tool denied with reason: *"Agent 'architect' may only edit files matching /\.md$/…"* | Hook stdout JSON contains `permissionDecision: deny`; file NOT created | +| **T-HOOK-02a (docs-writer ✅)** | docs-writer editing `.txt` allowed | `… -Agent docs-writer "create notes.txt with hello"` | File created | Allow | +| **T-HOOK-02b (docs-writer ❌)** | docs-writer editing `.py` denied | `… -Agent docs-writer "create notes.py with hello"` | Denied with policy reason | Deny + no file | +| **T-HOOK-03a (translate ✅)** | translate editing `.json` allowed | `… -Agent translate "create i18n.json with {}"` | File created | Allow | +| **T-HOOK-03b (translate ❌)** | translate editing `.yaml` denied | `… -Agent translate "create i18n.yaml with foo: bar"` | Denied | Deny + no file | +| **T-HOOK-04a (docs-extractor ✅)** | docs-extractor editing `.roo/extraction/x.yaml` allowed | `… -Agent docs-extractor "create .roo/extraction/x.yaml with foo: bar"` | File created | Allow | +| **T-HOOK-04b (docs-extractor ❌)** | docs-extractor editing root `x.yaml` denied | `… -Agent docs-extractor "create x.yaml with foo: bar"` | Denied (path outside `.roo/extraction/`) | Deny + no file | +| **T-CLI-CG11** | Sub-agent bypass (CG-11) is reproducible | From `orchestrator`: `copilot -p "use the task tool to dispatch architect to edit foo.ts"` | Sub-agent's edit **succeeds** (reproduces bug [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392)) | If edit succeeds → bug confirmed; rely on prose mitigation per § 8.6. If denied → bug fixed upstream; update playbook | + +### § 11.3 — Cross-cutting tests (5 rows) + +| ID | Claim | Test command | Expected | Pass criteria | +|---|---|---|---|---| +| **T-X-01** | `COPILOT_HOME` redirect works (vault portability) | `$env:COPILOT_HOME='C:\tmp\fake-home'; copilot --list-agents` | Empty list (no agents in fake home) | Confirms env var honored. Then unset and re-test → vault agents return | +| **T-X-02** | Generator round-trips Chat → CLI | `pwsh scripts/generate-cli-mcp.ps1 -DryRun` | Output JSON has `mcpServers:` top key, all `${input:…}` rewritten to `${ENV_VAR}` | No `${input:` strings remain in output | +| **T-X-03** | Generator handles unmapped input id (warning, not failure) | Add `${input:newKey}` to `.vscode/mcp.json`; run generator | Warning printed: *"No env-var mapping for Chat input id 'newKey'"*; placeholder preserved | Warn + non-zero exit only on hard JSON errors | +| **T-X-04** | Pre-commit hook regenerates on `.vscode/mcp.json` change | Edit `.vscode/mcp.json`; `git add .vscode/mcp.json; git commit -m test` | Hook output: *"[pre-commit] .vscode/mcp.json changed -> regenerating…"*; CLI file updated | Regen runs; commit succeeds | +| **T-X-05 (Q-039)** | Hook latency budget | `Measure-Command { 1..20 \| % { pwsh -NoProfile -File $env:COPILOT_HOME\hooks\enforce-file-regex.ps1 < empty.json } }` | Mean < 400 ms per call | Mean < 1 s acceptable; > 1 s = file Q-039 follow-up | + +### § 11.4 — Coverage summary + +| Surface | Tests | Notes | +|---|---|---| +| Chat | 8 (T-CHAT-01..08) | Includes G-1 known-limitation verification + Q-051 token-quote test | +| CLI core | 3 (T-CLI-01..03 + T-CLI-CG11) | Agent loading, MCP schema, BYOK, sub-agent bypass repro | +| CLI hooks (4 modes × 2) | 8 (T-HOOK-01a/b..04a/b) | Closes § 8.6 TODO; positive + negative per restricted mode | +| Cross-cutting | 5 (T-X-01..05) | Vault portability, generator round-trip, pre-commit, latency | +| **Total** | **24** | All four `Has fileRegex?` modes covered with positive + negative | + +**When to run what:** +- **Stage-1 → Stage-2 cutover:** entire matrix. +- **After any vault `.agent.md` edit:** T-CHAT-01, T-CLI-01. +- **After any MCP edit:** T-CHAT-03, T-CLI-02, T-X-02, T-X-04. +- **After any policy table change (§ 8.2):** all T-HOOK-*. +- **Monthly:** entire matrix (catches upstream regressions; especially T-CLI-CG11 which flips when [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) ships). + +--- + +## § 12 — Rollback Plan (Phase 8b-ii) + +The vault is **never modified** by §§ 1–10 — it remains the ground truth even after a full rollback. Rollback only undoes the Copilot-side consumer wiring (symlinks, env vars, project assets). Roo-Code is preserved as the 30-day fallback per [§ 1 step 6](#-1--pre-migration-checklist). + +### § 12.1 — Full rollback (return to Roo-Code-only state) + +Sequential checklist; safe in this order. Estimate: <10 minutes. + +```powershell +# 1. Re-enable Roo extension globally (if disabled per § 1 step 6). +# VS Code: Extensions view → search "Roo Code" → Enable. + +# 2. Remove symlinks from %USERPROFILE%\.copilot\ (vault is unaffected). +$cli = Join-Path $env:USERPROFILE '.copilot' +foreach ($name in @('agents','instructions','hooks.json','state','mcp-config.json')) { + $p = Join-Path $cli $name + if ((Test-Path $p) -and (Get-Item $p -Force).LinkType -eq 'SymbolicLink') { + Remove-Item $p -Recurse -Force + Write-Host " - removed symlink $p" + } +} + +# 3. Remove Chat user-scope agent symlinks (preserve hand-authored .prompt.md / .instructions.md). +$prompts = Join-Path $env:APPDATA 'Code\User\prompts' +Get-ChildItem $prompts -Filter '*.agent.md' -ErrorAction SilentlyContinue | ForEach-Object { + if ($_.LinkType -eq 'SymbolicLink') { + Remove-Item $_.FullName -Force + Write-Host " - removed $($_.Name)" + } +} + +# 4. Unset User-scope env vars. +foreach ($v in @('COPILOT_HOME','COPILOT_PROVIDER_TYPE','COPILOT_PROVIDER_BASE_URL', + 'COPILOT_PROVIDER_API_KEY','COPILOT_MODEL', + 'GITHUB_PAT','TAVILY_API_KEY','CONTEXT7_API_KEY','ADO_PAT')) { + [Environment]::SetEnvironmentVariable($v, $null, 'User') + Remove-Item "env:$v" -ErrorAction SilentlyContinue + Write-Host " - unset $v" +} + +# 5. Per-project: remove .vscode/mcp.json, .github/agents/, .github/instructions/ +# ONLY if you don't want to keep them for cross-tool use (AGENTS.md is also +# consumed by Claude Code / Codex / Cursor — usually worth keeping). +# Do NOT auto-delete; surface a manual review: +Write-Host "" +Write-Host "Manual review needed in each migrated project:" +Write-Host " - .vscode/mcp.json (delete OR keep for non-Roo MCP-aware tools)" +Write-Host " - .github/agents/ (delete OR keep for Claude Code / Codex)" +Write-Host " - .github/instructions/(delete OR keep — same rationale)" +Write-Host " - AGENTS.md (KEEP — cross-tool standard)" + +# 6. Restart VS Code; Roo-Code becomes default chat participant again. +# 7. Verify Roo-Code mode dropdown shows all vault modes. +``` + +**Vault preservation guarantee:** the script touches only `%USERPROFILE%\.copilot\`, `%APPDATA%\Code\User\prompts\.agent.md`, and User-scope env vars. `C:\git\roo-vault\` is never written to. Re-running `setup-copilot-vault.ps1` later restores the entire Copilot side. + +### § 12.2 — Partial rollback scenarios + +| Scenario | Trigger | Action | Keep | Drop | +|---|---|---|---|---| +| **Drop CLI side, keep Chat** | Hooks prove too brittle (Q-039 latency, CG-11 keeps biting) | Run § 12.1 steps 2 + 4 (cli vars only); leave Chat assets | `.vscode/mcp.json`, `.github/agents/`, `AGENTS.md`, Chat user-scope agent symlinks | `~/.copilot/`, `COPILOT_*` env vars, hook policy | +| **Drop Chat side, keep CLI** | G-1 prose enforcement repeatedly violated; user wants structural-only enforcement everywhere | Disable Chat agents (keep `.github/agents/` for CLI consumption); switch to Path B (Appendix B) | `~/.copilot/`, `COPILOT_HOME`, hooks, `.github/agents/` | Chat-side symlinks, `.vscode/mcp.json` (CLI uses generated `mcp-config.json` instead) | +| **Drop hooks, keep agents** | Hook latency unacceptable but agents still wanted | Set `disableAllHooks: true` in `~/.copilot/settings.json` (per [50 § 10.5](50-copilot-cli-research.md#105-disableallhooks-kill-switch--resolves-q-032)); leave `.agent.md` body prose as the only restricted-mode guard | All agents, MCP, BYOK | Hook enforcement (G-1 reverts to 🔴 on CLI) | +| **Drop BYOK** | Local model degrades quality vs GitHub-hosted | Unset `COPILOT_PROVIDER_*` env vars (§ 12.1 step 4 subset) | Everything else | Local model routing | + +### § 12.3 — Data preservation: where chat/session history lives + +| Surface | History location | Export procedure | +|---|---|---| +| Copilot Chat (VS Code) | Profile-state SQLite DB at `%APPDATA%\Code\User\globalStorage\github.copilot-chat\` (per [40 § Storage](40-copilot-chat-research.md)) | No documented export command (Q-029 open). Workaround: copy the entire `globalStorage\github.copilot-chat\` folder before rollback | +| Copilot CLI | `$COPILOT_HOME\session-state\` (NDJSON event logs) | Plain files; copy `$COPILOT_HOME\session-state\` to a backup folder before rollback | +| Roo-Code | `%APPDATA%\Code\User\globalStorage\rooveterinaryinc.roo-cline\` | Already backed up by § 1 step 5 backup script | + +**Recommended pre-rollback backup:** + +```powershell +$stamp = Get-Date -Format 'yyyyMMdd-HHmm' +$bak = "$HOME\copilot-rollback-backup-$stamp" +New-Item -ItemType Directory -Path $bak | Out-Null +Copy-Item -Recurse "$env:APPDATA\Code\User\globalStorage\github.copilot-chat" "$bak\chat-history" -ErrorAction SilentlyContinue +Copy-Item -Recurse "$env:COPILOT_HOME\session-state" "$bak\cli-history" -ErrorAction SilentlyContinue +Write-Host "Backup at $bak" +``` + +### § 12.4 — Sign-off criteria for "rollback complete" + +All must be true: + +1. ☑ VS Code Chat panel shows the **Roo-Code** participant by default (no Copilot custom agents in dropdown). +2. ☑ `gci env: | ? Name -like '*COPILOT*'` returns empty. +3. ☑ `Test-Path "$env:USERPROFILE\.copilot\agents"` returns `$false` OR returns a non-symlink directory you intend to keep. +4. ☑ Roo-Code mode picker shows all 17 vault modes after VS Code restart. +5. ☑ One round-trip task in Roo-Code completes successfully (e.g., switch to architect, ask for a plan, switch to code, implement). +6. ☑ Pre-rollback backup exists and is at least the size of the original `globalStorage` folder. +7. ☑ Decision-log entry filed naming the rollback trigger and date. + +--- + +## Appendix B — Path B (CLI-only) Fallback Playbook + +Per [`70 § 2.B`](70-migration-paths.md#-2b--path-b-copilot-cli-only) Path B scored **3.70** vs Path Hybrid's **3.90**. It is the documented Plan B if the Chat surface proves unsuitable. This appendix is intentionally **concise (~1 page)** — it references back to the main playbook rather than re-deriving content. + +### B.1 — When to switch to Path B (trigger conditions) + +Switch when **any** of the following becomes true: + +| Trigger | Detection | Why it forces Path B | +|---|---|---| +| **G-1 prose enforcement is repeatedly violated** | Audit chat history monthly; >2 violations of `architect`/`docs-writer`/`translate`/`docs-extractor` `fileRegex` over 30 days | Prose-only guard (Chat) is insufficient; CLI hooks are the only structural enforcement | +| **`chat.useAgentsMdFile` or custom-agents support is removed/regressed** | Chat behavior no longer matches [§ 3](#-3--chat-side-configuration) after VS Code update | The Chat side's value proposition collapses | +| **Multi-machine deterministic config required** | Adding 2+ developer machines + CI runners | CLI's `COPILOT_HOME` is cleaner than per-profile-id Chat symlinks (Q-026) | +| **Headless / CI-heavy workflow becomes primary** | >50% of agent invocations come from CI / cron / scripts | Chat surface is unused; maintaining it is overhead | +| **BYOK becomes mandatory for IDE work** | Cost / privacy / offline requirement | Chat doesn't honor `COPILOT_PROVIDER_*` (G-13 stays 🟠 on Chat) | + +### B.2 — What changes vs Path Hybrid + +| Component | Path Hybrid | Path B (CLI-only) | +|---|---|---| +| **Chat agents** | All 17 vault modes via `.github/agents/` | **Removed** — Chat reduced to vanilla Copilot Chat (no custom agents) | +| **CLI agents** | Same 17 modes shared via `.github/agents/` | Same 17 modes; now sole surface | +| **MCP source of truth** | `.vscode/mcp.json` (Chat) → generator → CLI mirror | `~/.copilot/mcp-config.json` directly (CLI-as-truth); no generator needed | +| **`fileRegex` enforcement** | CLI hooks for 4 modes; prose for Chat | CLI hooks for 4 modes (only surface; prose layer dropped) | +| **`AGENTS.md`** | Both surfaces | CLI only | +| **`.github/copilot-instructions.md`** | Chat only (CLI ignores) | **Drop** — replaced by `~/.copilot/copilot-instructions.md` | +| **Tool sets (`*.toolsets.jsonc`)** | Chat user-scope | Drop (CLI has no equivalent; inline `tools:` in `.agent.md`) | +| **Day-to-day surface** | VS Code Chat panel for interactive; CLI for automation | Terminal everywhere; VS Code as plain editor | + +### B.3 — Diff list against the main playbook + +**Sections that become unnecessary (skip entirely):** +- § 3 (Chat-side configuration) — no Chat surface to configure +- § 9 (MCP generator) — no schema fork to bridge +- § 10.1 step "Chat user-scope agent symlinks" — no Chat consumer +- T-CHAT-01..08 in § 11 — Chat-side validation N/A +- T-X-02..04 in § 11 — generator + pre-commit unused + +**Sections that become mandatory for ALL 17 modes (not just the 4 restricted ones):** +- § 7 (CLI-side configuration) — sole surface; every mode authored CLI-style +- § 8 (preToolUse hook) — extend the policy table to **all 17 modes** if any non-`fileRegex` policy is ever desired (e.g., command allowlists per mode) +- § 11.2 (CLI tests) — primary validation surface +- § 12.2 row "Drop Chat side, keep CLI" — becomes the default state, not an option + +**New section needed (Path B only):** +- **B.4 — Reduced Chat configuration:** disable VS Code custom agents to avoid stale-config confusion: set `"chat.agent.enabled": false`, `"chat.useAgentsMdFile": false` in `%APPDATA%\Code\User\settings.json`. Keep MCP and inline chat working as default Copilot experience. + +### B.4 — Migration cost: Path Hybrid → Path B + +**Effort estimate: small (~½ to 1 day)** because the CLI side already exists. + +| Step | Effort | Notes | +|---|---|---| +| Disable Chat custom agents (one settings flip) | 5 min | `"chat.agent.enabled": false` | +| Remove Chat user-scope agent symlinks (§ 12.2 row 2) | 10 min | Run § 12.1 step 3 | +| Promote `~/.copilot/mcp-config.json` to source of truth | 30 min | Stop running generator; hand-edit going forward; archive `.vscode/mcp.json` | +| Move `.github/copilot-instructions.md` content into `$COPILOT_HOME/copilot-instructions.md` | 15 min | Verbatim copy | +| Optional: extend hook policy table to non-`fileRegex` modes | 1–2 hr | Only if new restrictions desired | +| Re-run § 11.2 + § 11.3 validation matrix | 30 min | Confirm CLI side fully functional | + +**Net new effort vs Path Hybrid:** none for the agent side; the savings come from dropping the generator and Chat dual-maintenance. + +### B.5 — Reverse migration (Path B → Path Hybrid) if Chat catches up + +If Chat ships structural `fileRegex` enforcement (G-1 closes) or otherwise becomes acceptable: + +1. Re-enable Chat custom agents (`"chat.agent.enabled": true`). +2. Re-run `setup-copilot-vault.ps1` (idempotent — recreates Chat user-scope symlinks). +3. Re-author `.vscode/mcp.json` from current `~/.copilot/mcp-config.json` by reversing the § 9.1 generator (rename `mcpServers` → `servers`; replace `${ENV_VAR}` with `${input:id}` and add `inputs:` array). +4. Run § 11.1 (Chat tests) to validate. +5. File a decision-log entry recording the trigger that justified the reverse. + +**Reverse effort: ~1 day** (the `.vscode/mcp.json` re-author is the largest single piece since it's hand-edited rather than generated). + +--- + +## Cross-links + +- [`60-gap-analysis.md`](60-gap-analysis.md) · [`70-migration-paths.md`](70-migration-paths.md) · [`90-decision-log.md`](90-decision-log.md) · [`99-open-questions.md`](99-open-questions.md) +- Vault entry points: [`../../../../roo-vault/global-settings/custom_modes.yaml`](../../../../roo-vault/global-settings/custom_modes.yaml) · [`../../../../roo-vault/global-settings/mcp_settings.json`](../../../../roo-vault/global-settings/mcp_settings.json) · [`../../../../roo-vault/setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1) +- Phase 8b-i sources: [`50-copilot-cli-research.md` § 2 / § 4 / § 5 / § 9 / § 10](50-copilot-cli-research.md) · [`20-roo-vault-inventory.md` § MCP Server Inventory](20-roo-vault-inventory.md) +- Phase 8b-ii sources: [`70-migration-paths.md` § 2.B + § 4](70-migration-paths.md) (Path B fallback) · [`60-gap-analysis.md`](60-gap-analysis.md) (validation matrix gap-coverage) diff --git a/docs/investigation/roo-to-copilot/90-decision-log.md b/docs/investigation/roo-to-copilot/90-decision-log.md new file mode 100644 index 00000000000..b314bcdee9a --- /dev/null +++ b/docs/investigation/roo-to-copilot/90-decision-log.md @@ -0,0 +1,716 @@ +--- +phase: all +status: closed +owner: architect-phase-9 +last_updated: 2026-04-26 +sources: [] +--- + +# Decision Log (append-only) + +> Parent plan: [`00-plan.md`](00-plan.md) · Index: [`README.md`](README.md) + +**Rules:** +- Append-only. Never edit or delete prior entries; supersede with a new dated entry that links back. +- One decision per entry. +- Use the heading format `## YYYY-MM-DD HH:MM — ` (UTC or local with offset noted). +- Required subsections: **Context · Decision · Rationale · Consequences · Status**. +- `Status` is one of: `proposed`, `accepted`, `superseded by `, `rejected`. + +--- + +## 2026-04-26 13:52 — Investigation kicked off; memory scaffolding created + +**Context** + +The user wants to leave Roo-Code and recreate the same experience using GitHub Copilot Chat and/or Copilot CLI, possibly via Squad as an intermediary. To support a long-running, multi-session investigation, persistent memory files are required so future agents/sessions can resume work without re-deriving context. + +**Decision** + +Create the memory-file scaffold under [`docs/investigation/roo-to-copilot/`](.) with: + +- [`README.md`](README.md) — index and usage rules. +- [`00-plan.md`](00-plan.md) — 9-phase investigation plan and methodology. +- [`10-roo-inventory.md`](10-roo-inventory.md), [`20-roo-vault-inventory.md`](20-roo-vault-inventory.md), [`30-squad-inventory.md`](30-squad-inventory.md) — Phase 1–3 templates. +- [`40-copilot-chat-research.md`](40-copilot-chat-research.md), [`50-copilot-cli-research.md`](50-copilot-cli-research.md) — Phase 4–5 templates. +- [`60-gap-analysis.md`](60-gap-analysis.md), [`70-migration-paths.md`](70-migration-paths.md), [`80-migration-playbook.md`](80-migration-playbook.md) — Phase 6–8 templates. +- [`90-decision-log.md`](90-decision-log.md) — this log. +- [`99-open-questions.md`](99-open-questions.md) — running unresolved questions, pre-seeded. + +No findings have been pre-filled. Every templated file carries YAML front-matter (`phase`, `status: not-started`, `owner: tbd`, `last_updated: 2026-04-26`, `sources: []`) and per-section "What goes here" guidance. + +**Rationale** + +- A fixed file taxonomy prevents future agents from reorganizing mid-investigation. +- Append-only decision log + dated open-questions list preserve history under multi-session work. +- Phase numbering (10/20/…/90) leaves room for inserts (e.g. `15-`, `45-`) without renumbering. +- Methodology rules (cite, quote primary docs, mark uncertainty) are codified up front so they apply to all future entries. + +**Consequences** + +- Future subtasks should pick up at Phase 1 ([`10-roo-inventory.md`](10-roo-inventory.md)) and proceed in numeric order, updating front-matter and the status table in [`README.md`](README.md) as they go. +- Any deviation from the plan in [`00-plan.md`](00-plan.md) requires a new decision-log entry. + +**Status** + +`accepted` + +--- + +## 2026-04-26 14:05 — Phase 1 (Roo-Code inventory) complete + +**Context** + +Phase 1 of the investigation requires a workspace-only inventory of Roo-Code features that need to be replicated when migrating off Roo. No web research was used; only files under `c:/git/Roo-Code` and the user's VS Code globalStorage settings were inspected. + +**Decision** + +Populate [`10-roo-inventory.md`](10-roo-inventory.md) with concrete findings covering: 5 built-in modes ([`packages/types/src/mode.ts`](../../../packages/types/src/mode.ts)), the layered custom-mode mechanism ([`.roomodes`](../../../.roomodes) + global [`custom_modes.yaml`](../../../../../Users/bertanari/AppData/Roaming/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/custom_modes.yaml)), orchestrator behavior, MCP integration with per-mode `allowedMcpServers` allowlists ([`docs/design/per-mode-mcp-settings.md`](../../design/per-mode-mcp-settings.md)), rules/custom-prompts loading ([`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts)), the 22-tool native tool surface ([`src/core/prompts/tools/native-tools/`](../../../src/core/prompts/tools/native-tools)), Windows settings storage paths, and webview UI features. + +**Rationale** + +- The inventory is required as the baseline against which Copilot Chat (Phase 4) and Copilot CLI (Phase 5) will be measured. +- Limiting to local sources keeps findings reproducible and citable; no external links to age out. + +**Consequences** + +- **Headline finding:** Roo's "experience" is the composition of (a) layered modes (built-in → global YAML → project `.roomodes`), (b) per-mode tool-group + file-regex restrictions, (c) per-mode MCP allowlist, (d) layered rules from `~/.roo/`, project `.roo/`, `AGENTS.md`, and (e) sequential `new_task` orchestrator boomerang — replicating it requires parity on all five axes, not just "modes". +- Roo's global rules directory is `~/.roo` (homedir, see [`src/services/roo-config/`](../../../src/services/roo-config)), distinct from VS Code globalStorage which only holds `custom_modes.yaml` and `mcp_settings.json`. + +**Status** + +`accepted` + +--- + +## 2026-04-26 14:06 — Phase 2 (roo-vault inventory) complete + +**Context** + +Phase 2 catalogs the user's personal `c:/git/roo-vault` repository, which centralizes shared Roo-Code configuration across multiple projects via symlinks. Only local files were inspected; secrets in MCP settings were redacted. + +**Decision** + +Populate [`20-roo-vault-inventory.md`](20-roo-vault-inventory.md) with the vault's layered composition model documented in [`../roo-vault/README.md`](../../../../roo-vault/README.md), the 17 modes in [`../roo-vault/global-settings/custom_modes.yaml`](../../../../roo-vault/global-settings/custom_modes.yaml), the 7 MCP servers in [`../roo-vault/global-settings/mcp_settings.json`](../../../../roo-vault/global-settings/mcp_settings.json) (4 enabled, 3 disabled, secrets redacted), per-project `.roomodes` overrides under `../roo-vault/projects/`, and the symlink bootstrap in [`../roo-vault/setup-vault.ps1`](../../../../roo-vault/setup-vault.ps1). + +**Rationale** + +- The vault — not the Roo extension — is the actual surface area the user must migrate. A successful migration must preserve the multi-project layered composition, not just the modes themselves. +- The user's task brief referenced `setup/setup_dev_box.ps1`; on inspection that script is a dev-box bootstrap (Chocolatey/WSL/Docker/Qdrant/LiteLLM). The actual vault wiring script is `setup-vault.ps1` at the repo root. Both are documented to avoid future confusion. + +**Consequences** + +- **Headline finding:** The vault uses **directory symlinks** to share `global-settings/`, `.roo/`, `.roomodes`, `.clinerules`, and per-project `myplans/` into each project. Any migration target must offer an equivalent "one settings tree, many projects" composition or the user loses the multi-project parity that makes the vault valuable. +- 17 vault modes vs 5 Roo built-ins — most modes are user-authored (docs-writer, security, design-reviewer, review-addresser, code-reviewer, task-filer, builder, tester, pull-requestor, devops, etc.) and are the real migration unit. + +**Status** + +`accepted` + +--- + +## 2026-04-26 14:43 — Phase 4a (Copilot custom agents + custom instructions) complete + +**Context** + +Phase 4 of the investigation requires researching GitHub Copilot Chat in VS Code as a candidate replacement for Roo. Phase 4a covers two of the four sub-areas: **custom chat modes** (now renamed by Microsoft to **custom agents** / `.agent.md`) and **custom instructions** (`copilot-instructions.md`, `.instructions.md`, `AGENTS.md`, settings-based keys). Phases 4b (prompt files), 4c (MCP, tool sets, agent mode), and 4d (chat participants, storage, limits) remain pending. + +**Decision** + +Populate the **Custom Chat Modes** and **Custom Instructions** sections of [`40-copilot-chat-research.md`](40-copilot-chat-research.md) with primary-source findings cited to [`code.visualstudio.com/docs/copilot/customization/custom-chat-modes`](https://code.visualstudio.com/docs/copilot/customization/custom-chat-modes), [`code.visualstudio.com/docs/copilot/customization/custom-instructions`](https://code.visualstudio.com/docs/copilot/customization/custom-instructions), and the GitHub-side [`docs.github.com .../add-repository-instructions`](https://docs.github.com/en/copilot/how-tos/configure-custom-instructions/add-repository-instructions). Set the file's status to `in-progress` (not `complete`) and add a `` marker. + +**Rationale** + +- Microsoft renamed `.chatmode.md` → `.agent.md` and `.github/chatmodes/` → `.github/agents/`; failing to capture this would have left the playbook (Phase 8) pointing at obsolete file paths. +- The two Copilot capabilities that block-or-unblock the largest chunks of Roo parity (per-mode tool/MCP allowlists, sub-agents, AGENTS.md ingestion) all live in these two sections, so resolving them early de-risks the remaining gap analysis. + +**Consequences** + +- **Headline finding (chatmodes/agents):** Copilot custom agents **match Roo on per-mode tool & MCP allowlists** (`tools: ['mcpserver/*']`) and **partially match Roo's orchestrator** via the `agent` tool + `agents:` frontmatter + handoff buttons, but offer **no equivalent to Roo's `fileRegex` per-tool-group file-edit restriction** — that capability is lost in any Path-A migration and must be enforced via prose instructions. +- **Headline finding (instructions):** `AGENTS.md` is **natively supported in VS Code Copilot Chat** (toggled by `chat.useAgentsMdFile`, default on), Copilot's precedence is **Personal > Repository > Organization** with all matching files concatenated within a tier, and Roo's per-mode rules folder (`.roo/rules-/`) has **no first-class equivalent** — it must be inlined into each agent body or composed via Markdown-linked `.instructions.md` files. +- Open questions Q-002, Q-003, Q-004 are now resolved; Q-005 is partially resolved with a documented lossy-fields list. Three new questions (Q-015 user-data path discrepancy, Q-016 release-version provenance for the rename, Q-017 instructions size cap, Q-018 per-mode rules folder mapping) opened in [`99-open-questions.md`](99-open-questions.md). +- Phase 4 status badge in [`README.md`](README.md) advanced from `not-started` to `in-progress (4a done)`. + +**Status** + +`accepted` + +--- + +## 2026-04-26 14:54 — Phase 4b (Copilot prompt files + tool sets) complete + +**Context** + +Phase 4b populates the **Prompt files** and **Tool sets** sections of [`40-copilot-chat-research.md`](40-copilot-chat-research.md) with primary-source findings, leaving 4c (MCP, agent mode) and 4d (chat participants, storage, limits) for follow-up subtasks. + +**Decision** + +Cite the canonical VS Code docs ([`prompt-files`](https://code.visualstudio.com/docs/copilot/customization/prompt-files), [`agent-tools`](https://code.visualstudio.com/docs/copilot/agents/agent-tools), [`concepts/tools`](https://code.visualstudio.com/docs/copilot/concepts/tools)) plus GitHub issues confirming Windows storage paths and limits ([`microsoft/vscode#251603`](https://github.com/microsoft/vscode/issues/251603), [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515), [`vscode-copilot-release#13065`](https://github.com/microsoft/vscode-copilot-release/issues/13065), [`vscode-copilot-release#12853`](https://github.com/microsoft/vscode-copilot-release/issues/12853)). Update the file's marker comment to `4a + 4b complete`, advance the README Phase-4 badge accordingly. + +**Rationale** + +- Tool sets are **the closest analogue to Roo's per-mode `groups` + `allowedMcpServers`** allowlist; nailing down their schema, location, and limits unlocks the converter design in Phase 8 and the gap matrix in Phase 6. +- Prompt files are largely additive over Roo (Roo has no first-class equivalent), but they materially affect how user-facing slash commands / templated subtasks should be emitted by any `.roomodes`-to-Copilot converter. + +**Consequences** + +- **Headline finding (prompt files):** prompt files (`*.prompt.md`) are workspace-scoped at `.github/prompts/` and user-scoped at `%APPDATA%\Code\User\prompts\` on Windows (same folder as `.instructions.md`, user-scope `.agent.md`, and `*.toolsets.jsonc`). Frontmatter has `agent` (not `mode`) — used to bind the prompt to a built-in or custom `.agent.md`; when both prompt and agent declare `tools`, **prompt-file `tools` win** (widening, not narrowing, the agent's allowlist). Parameterization is **free-text-after-slash only** (`/promptname formName=Foo`); no documented `${input:name}` substitution; sub-prompt composition is via Markdown links to other prompt files. Prompt files are still in **public preview** and **not** picked up by Copilot CLI. +- **Headline finding (tool sets):** `*.toolsets.jsonc` files are **user-scope only** today (`%APPDATA%\Code\User\prompts\` on Windows; workspace storage tracked in [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515) but **not yet shipped**). Schema is `{ "": { tools, description, icon } }`. Sets are referenced from `.agent.md` / `.prompt.md` `tools:` arrays as bare names alongside built-in tools and `mcpserver/*` wildcards. **Tool sets + agent `tools:` array fully replicate Roo's `groups` + `allowedMcpServers`** *except* for (a) `fileRegex` per-tool-group restrictions (still no equivalent — restated from 4a) and (b) workspace-scoped reusable tool-set **files** (workaround: inline tool lists in `.github/agents/*.agent.md`). The 128-tool-per-request hard cap is still enforced ([`vscode-copilot-release#13065`](https://github.com/microsoft/vscode-copilot-release/issues/13065)) and applies to the flattened total, not the number of tool-set references. +- New questions Q-019 (prompt-file keybinding args), Q-020 (variable substitution), Q-021 (workspace-scoped toolsets), Q-022 (wildcard-in-toolset), Q-023 (toolset nesting), Q-024 (toolsets in Settings Sync) opened in [`99-open-questions.md`](99-open-questions.md). Q-002 and Q-005 were already partially or fully resolved in 4a; this section adds further confirmation but does not change their status. +- Phase 4 status badge in [`README.md`](README.md) advanced from `in-progress (4a done)` to `in-progress (4a + 4b done)`. + +**Status** + +`accepted` + +--- + +## 2026-04-26 15:09 — Phase 4c (Copilot MCP support + Windows storage paths) complete + +**Context** + +Phase 4c populates the **MCP support** and **Storage Locations (Windows)** sections of [`40-copilot-chat-research.md`](40-copilot-chat-research.md), leaving 4d (Agent mode, Chat participants/Extension API, Limits/known gaps) for a follow-up subtask. + +**Decision** + +Cite the canonical VS Code docs ([`docs/copilot/customization/mcp-servers`](https://code.visualstudio.com/docs/copilot/customization/mcp-servers), [`docs/copilot/reference/mcp-configuration`](https://code.visualstudio.com/docs/copilot/reference/mcp-configuration), [`api/extension-guides/ai/mcp`](https://code.visualstudio.com/api/extension-guides/ai/mcp)), the GitHub-side companion ([`docs.github.com — extending Copilot Chat with MCP`](https://docs.github.com/en/copilot/customizing-copilot/extending-copilot-chat-with-mcp)), the auto-approve / trust UX ([`microsoft/vscode#253039`](https://github.com/microsoft/vscode/issues/253039), [`docs/copilot/agents/agent-tools`](https://code.visualstudio.com/docs/copilot/agents/agent-tools)), and the Windows `npx`/`.cmd` quirk ([`modelcontextprotocol/servers#3460`](https://github.com/modelcontextprotocol/servers/issues/3460)). Document the consolidated Storage-Locations table with profile-aware paths. Update the file's marker comment to `4a + 4b + 4c complete; 4d pending`, advance the README Phase-4 badge accordingly. + +**Rationale** + +- MCP is the highest-leverage Roo feature surface (per-mode tool restriction + cross-project tool reuse via the vault), and a clear `mcp.json` schema map plus a `${input:…}` secret-prompt pattern unlocks the vault commit-safe migration in Phase 8. +- Resolving the **profile-scoping question** for `mcp.json` (yes, profile-scoped) vs the `prompts/` folder (no, global) was a prerequisite for designing the Phase-8 symlink scheme, since the user's vault depends on `mklink /D` automation. + +**Consequences** + +- **Headline finding (`.vscode/mcp.json`):** schema is `{ servers: { … }, inputs: [ … ] }`. Per-server fields differ by transport — stdio (`type`/`command`/`args`/`env`/`envFile`/`sandboxEnabled`/`sandbox`) and HTTP/SSE (`type`/`url`/`headers`). Sandboxing is **macOS/Linux only** (silently ignored on Windows). Three transports: `stdio`, `http` (Streamable HTTP), `sse` (legacy). VS Code falls back from `http` to `sse`. There is **no top-level `gallery` or `dev` key** — the gallery is a UX surface; `dev` is per-server. +- **Headline finding (secret pattern):** the `${input:id}` placeholder + `inputs: [{ type: "promptString", id, description, password }]` array is the **commit-safe** pattern. VS Code prompts at first-run, stores the value in Windows Credential Manager, and re-uses it silently. **`.vscode/mcp.json` should be committed** (with placeholders), per explicit doc guidance: *"Avoid hardcoding sensitive information like API keys. Use input variables or environment files instead."* This collapses Roo's two-file split (gitignored `mcp_settings.json` + committed `.roo/mcp.json`) into one. +- **Headline finding (per-agent filtering):** **There is no separate `allowedMcpServers` setting** — restriction is performed entirely via `.agent.md` `tools: ["server/*"]` (Phase 4a) and `*.toolsets.jsonc` `tools: [...]` (Phase 4b). Roo's `allowedMcpServers: ["github"]` ↔ Copilot's `tools: ["github/*"]` is a direct 1:1. +- **Headline finding (auto-import):** `chat.mcp.discovery.enabled` (off by default) imports MCP server configs from other clients — Claude Desktop confirmed; Cursor/Continue/Windsurf inferred from community reports (filed as Q-025). Useful for migration **from** other AI clients but not strictly needed for the Roo→Copilot path. +- **Headline finding (storage):** consolidated Windows path table now lives in [`40-copilot-chat-research.md` § Storage Locations (Windows)](40-copilot-chat-research.md#storage-locations-windows). Key insight: **`mcp.json` and `settings.json` are profile-scoped** (`%APPDATA%\Code\User\profiles\\…`); the **`prompts/` folder** (covering agents, prompts, instructions, tool sets) is **global** (`%APPDATA%\Code\User\prompts\`). The vault symlink scheme works as-is for the global folder; per-profile `mcp.json` requires a small Phase-8 PowerShell helper (filed as Q-026). +- **Headline finding (Windows quirks):** `npx`-based stdio servers can fail when launched from VS Code if `nvm-windows` hides `npx.cmd` from the launched-from-shortcut env; workaround is absolute path or `cmd /c`. `mcp.json` does **not** expand literal `%APPDATA%`; use `${env:APPDATA}` or `${userHome}`. Docker stdio servers must not use `-d` (detach). +- **Roo→Copilot MCP migration sketch (4 steps):** + 1. Move `~/AppData/Roaming/Code/User/globalStorage/rooveterinaryinc.roo-cline/settings/mcp_settings.json` → `%APPDATA%\Code\User\mcp.json` (rename `mcpServers` → `servers`). + 2. Move project `.roo/mcp.json` → `.vscode/mcp.json` (same rename). + 3. Replace inline tokens with `${input:…}` placeholders; declare each placeholder in the top-level `inputs` array with `password: true`. + 4. Restrict per-agent access via `.github/agents/.agent.md` `tools: ["servername/*"]` instead of `.roomodes` `allowedMcpServers`. +- Open questions resolved: **Q-009** (empty `allowedMcpServers` array means "no MCP"), **Q-015** (partial — `mcp.json` profile-scoped, `prompts/` global), **Q-008** (partial — symlink portability confirmed for Copilot Chat). New questions opened: **Q-025** (residual MCP unknowns), **Q-026** (multi-profile vault symlink automation). +- Phase 4 status badge in [`README.md`](README.md) advanced from `in-progress (4a + 4b done)` to `in-progress (4a + 4b + 4c done — agents/instructions, prompt files, tool sets, MCP, Windows storage paths)`. + +**Status** + +`accepted` + +--- + +## 2026-04-26 14:07 — Phase 3 (Squad inventory) complete + +**Context** + +Phase 3 inventories Squad at `c:/git/squad` to determine what it actually is and how it relates to GitHub Copilot and Roo-Code. Findings sourced from the Squad README, package manifests, `.copilot/` config, and the pre-existing analysis at [`docs/analysis/squad-vs-roo-comparison.md`](../../analysis/squad-vs-roo-comparison.md). + +**Decision** + +Populate [`30-squad-inventory.md`](30-squad-inventory.md) with: Squad's identity as a Node CLI + SDK monorepo (npm `@bradygaster/squad-cli` + `@bradygaster/squad-sdk` v0.9.1, alpha), its dependency on `@github/copilot-sdk` ([`../squad/packages/squad-sdk/package.json`](../../../../squad/packages/squad-sdk/package.json)), its invocation pattern via `copilot --agent squad`, the 17 CLI commands documented in [`../squad/README.md`](../../../../squad/README.md), parallel orchestration primitives (fan-out, session-pool, wave-dispatch, fleet-dispatch), Ralph watch-mode automation, persistent named agents from a casting registry, `.squad/` markdown state, and `.copilot/mcp-config.json` MCP pass-through. + +**Rationale** + +- Squad does not replace Copilot — it **drives** Copilot CLI via `@github/copilot-sdk`. Evaluating it in isolation would be wrong; it is one of the candidate orchestration layers for Path C/D. +- The pre-existing comparison doc already enumerates feature deltas with file citations and was leveraged rather than duplicated. + +**Consequences** + +- **Headline finding:** Squad is a **parallel-by-default** Copilot CLI orchestrator with persistent named agents and committed markdown state. Roo is **sequential-by-design** with isolated `new_task` boomerangs. They occupy adjacent but distinct niches: Squad supplies parallel fan-out + Copilot integration that Roo lacks, but offers no Roo-style per-mode tool/file-regex/MCP restrictions, no webview UI, and no layered rules system. Squad is alpha (v0.9.1) — production migration risk is non-trivial. +- Phase 7 (migration paths) must consider Squad as a *supplement* to Copilot Chat/CLI rather than a peer alternative. + +**Status** + +`accepted` + +--- + +## 2026-04-26 15:30 — Phase 4d (Agent mode + Chat participants/Extension API + Limits/Gap Catalog) complete; Phase 4 closed + +**Context** + +Phase 4d was the final sub-phase of the Copilot Chat research stream. It covered three remaining surfaces from the [`00-plan.md`](00-plan.md) Phase-4 outline: (a) agent mode and sub-agents (`runSubagent`, `agents:` allowlist, recursion, handoffs, max-iterations, terminal auto-approve, background tasks), (b) chat participants and the chat-extension API (`vscode.chat.createChatParticipant`, Language Model Tools API, Agent Plugins Preview channel), and (c) a synthesised Gap Catalog with severities feeding directly into Phase 6. + +**Decision** + +Close Phase 4 with all four sub-phases (4a + 4b + 4c + 4d) complete. Headline conclusions captured in [`40-copilot-chat-research.md`](40-copilot-chat-research.md): + +- **Agent mode parity is high.** `chat.agent.maxRequests` defaults to 25; the tool-calling loop, working set, checkpoints, and per-tool approval policies (Default Approvals / Bypass Approvals / Autopilot) collectively cover Roo's `new_task` boomerang plus add capabilities Roo does not have (parallel sub-agent dispatch, multi-model consensus, fork-conversation, edit-previous-request). +- **Sub-agents resolve Q-013.** `runSubagent` is parallel-by-default; sequential semantics are achievable only by prose discipline in the parent agent's body. Recursion is supported up to depth 5 via `chat.subagents.allowInvocationsFromSubagents`. Handoffs (`handoffs:` frontmatter) are user-mediated next-step buttons, not model-driven returns — that is, similar in spirit to Roo's boomerang but interactive rather than automatic. +- **Chat extension API supports Plan-B.** A 3rd-party extension can ship a Roo-equivalent declarative experience via Agent Plugins (Preview, gated by `chat.agentPlugins.enabled`); the stable surfaces are `vscode.chat.createChatParticipant` + the Language Model Tools API + `contributes.languageModelTools`. Reference exemplar: [`microsoft/vscode-extension-samples/chat-sample`](https://github.com/microsoft/vscode-extension-samples/tree/main/chat-sample). Vault-as-VSIX (Path D in Phase 7) is technically viable. +- **Gap Catalog: 1 blocker, 3 major, ≥6 minor, ≥12 wins.** Only 🔴 G-1 (per-mode `fileRegex` edit restrictions) has no first-class equivalent and is the sole genuine migration blocker. 🟠 majors: per-mode rules folder (G-2), workspace-scoped `*.toolsets.jsonc` (G-3), chat history export (G-9), local model providers (G-13). Multiple Copilot-only wins (W-1..W-12) — model selection, .agent.md via VSIX, .prompt.md slash commands, MCP secret hygiene, AGENTS.md cross-tool, cloud-agent reuse, parallel sub-agents, checkpoints, URL approval pre/post, org policies, unified panel, agent-type hand-off — net upside from a Copilot migration. + +Bookkeeping completed in this entry's pass: + +- Frontmatter on [`40-copilot-chat-research.md`](40-copilot-chat-research.md) flipped to `status: complete`; Phase-4d source URLs appended to `sources:`; marker comment updated to ``. +- [`README.md`](README.md) Phase-4 badge flipped from 🟡 in-progress to ✅ complete. +- [`99-open-questions.md`](99-open-questions.md): **Q-013** marked RESOLVED (parallel-by-default sub-agents); **Q-014** marked PARTIALLY RESOLVED (unified panel; user-input still needed); added **Q-027** (extension manifest path outside Agent Plugins Preview), **Q-028** (org-management story for Agent Plugins), **Q-029** (chat-sessions JSON portability), **Q-030** (vault dependence on non-Copilot model providers). + +**Rationale** + +Phase 4 is the load-bearing research stream — it determines whether VS Code Copilot Chat alone can carry the vault, or whether Squad / a custom VSIX is required. With one blocker, three majors, and a clear set of wins, the migration is **justified**: a Copilot-Chat-first path is viable provided G-1 (per-mode file-regex) is addressed by either (i) accepting the loss, (ii) wrapping with hand-rolled `applyTo`-glob instructions per agent, or (iii) shipping a thin VSIX that reads `.roomodes`-style restrictions. Phase 6 will turn the Gap Catalog into a per-feature decision matrix, and Phase 7 will weigh Paths A (Copilot Chat only) / B (Copilot Chat + Squad) / C (Copilot CLI only) / D (vault-as-VSIX) using these severities. + +**Consequences** + +- Phase 5 (Copilot CLI research) is unblocked and is the next active phase per the [`00-plan.md`](00-plan.md) ordering. +- Phase 6 (gap analysis) inherits the Gap Catalog from § Limits / Known Gaps in [`40-copilot-chat-research.md`](40-copilot-chat-research.md) as its starting matrix. +- Phase 7 (migration paths) gains the Plan-B viability finding (extension-shipped agents) and must explicitly evaluate Path D against Q-027 / Q-028. +- Phase 8 (playbook) inherits Q-029 (sessions portability) and Q-026 (multi-profile `mcp.json` symlink helper) as concrete script-writing tasks. +- The user must answer Q-030 (does the vault use a non-Copilot model today?) before Phase 7 path selection. + +**Status** + +`accepted` + +--- + +## 2026-04-26 15:42 — Phase 5a (Copilot CLI identity/install + agent loop + customization + Squad cross-ref + Roo↔CLI mapping) complete + +**Context** + +Phase 5 of the investigation researches the GitHub Copilot CLI as a candidate replacement for Roo. Phase 5a covers five of the file's planned sub-areas: (1) **Identity & disambiguation** (`@github/copilot` standalone CLI vs the legacy `gh copilot` extension — they are different products), (2) **Install & authentication** on Windows 11, (3) **Storage locations** under `%USERPROFILE%\.copilot\`, (4) **Agent loop** (modes, permissions, headless flags, sessions, built-in tools), (5) **Customization** (custom instructions cascade + custom agents + `--agent` precedence), plus a **Squad cross-reference** that resolves Q-010 and a complete **Roo ↔ Copilot CLI mapping table** across 25 axes. Phase 5b (deep MCP, hooks, skills, exhaustive SDK surface, full Gap Catalog) remains pending. + +**Decision** + +Populate [`50-copilot-cli-research.md`](50-copilot-cli-research.md) with primary-source findings cited to: + +- [`npmjs.com/package/@github/copilot`](https://www.npmjs.com/package/@github/copilot) (CLI v1.0.36) and [`npmjs.com/package/@github/copilot-sdk`](https://www.npmjs.com/package/@github/copilot-sdk) (SDK v0.3.0) — package identity, install methods, system requirements. +- [`docs.github.com — about-copilot-cli`](https://docs.github.com/en/copilot/concepts/agents/copilot-cli/about-copilot-cli) — concepts, modes, BYOK. +- [`docs.github.com — install-copilot-cli`](https://docs.github.com/en/copilot/how-tos/copilot-cli/install-copilot-cli) and [`cli-best-practices`](https://docs.github.com/en/copilot/how-tos/copilot-cli/cli-best-practices) — install + auth + best practices. +- [`docs.github.com — cli-config-dir-reference`](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-config-dir-reference) — full directory layout, settings cascade, `COPILOT_HOME` semantics. +- [`docs.github.com — cli-command-reference`](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-command-reference) and [`run-cli-programmatically`](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically) — slash commands, flags, headless patterns, exit codes. +- [`docs.github.com — use-custom-instructions`](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-custom-instructions) and [`use-custom-agents`](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/use-custom-agents) — instruction cascade + agent discovery + frontmatter. +- [`../squad/.copilot/mcp-config.json`](../../../../squad/.copilot/mcp-config.json) and [`../squad/packages/squad-sdk/package.json`](../../../../squad/packages/squad-sdk/package.json) — squad's actual config and SDK dependency. + +Set the file's status to `in-progress` (not `complete`) with marker comment ``. Advance the README Phase-5 badge to 🟡 in-progress with the same sub-phase summary. + +**Rationale** + +- The 5a sub-areas are the load-bearing surfaces for Phase-7 path selection: install/auth determines whether the user can run the CLI at all on the dev box; storage/`COPILOT_HOME` determines whether the vault's symlink-and-commit pattern survives; the agent loop + customization + mapping determine whether the vault's 17 modes can be migrated 1:1. +- Resolving the **identity question first** (`gh copilot` extension is **not** the migration target) prevents the rest of the document — and the eventual playbook — from being written against an obsolete product. +- The **Roo↔CLI mapping table** in § 8 (25 axes; 22 🟢 / 2 🟡 / 2 🔴) is the direct input to Phase 6's gap matrix and Phase 7's path selection. Producing it in 5a (rather than deferring to 5b) accelerates the next two phases. +- Squad cross-reference (§ 6) had to land in 5a because three downstream questions (Q-010, Q-031 squad's non-standard MCP location, vault-on-CLI bootstrap) all depend on knowing what squad actually does on top of the CLI. + +**Consequences** + +- **Headline finding (identity):** **The `@github/copilot` npm package is the migration target; the legacy `gh copilot` extension is not.** They have different binaries (`copilot` vs `gh copilot`), different config dirs, different model surfaces, and different agentic capabilities. Any prior thinking that conflated them is invalid; the playbook must be explicit. +- **Headline finding (portability — resolves Q-008):** **`COPILOT_HOME` is the load-bearing primitive.** A single env var (or per-invocation `--config-dir` flag) redirects every config sub-path — settings, agents, skills, instructions, hooks, MCP, sessions. The vault bootstrap collapses to `[Environment]::SetEnvironmentVariable("COPILOT_HOME", "/global-settings/copilot", "User")`. No per-profile-id complexity (cf. Chat-side Q-026). This is materially **simpler** than the Chat-side symlink scheme. +- **Headline finding (squad — resolves Q-010):** **Squad has zero `vscode.lm` / `vscode` / `@vscode/*` dependencies.** It is strictly external CLI-driven via `@github/copilot-sdk`. Squad therefore cannot be embedded into a VS Code extension as-is; Path-D (vault-as-VSIX) cannot reuse squad without re-implementing its orchestration on top of `vscode.lm`. Path-C (CLI-only) and Path-B (Chat + CLI) can both adopt squad as an external layer. +- **Headline finding (mapping — 25 axes):** Of 25 Roo features, **22 are 🟢 (1:1 or better) on the CLI, 2 🟡 (minor nuance), 2 🔴 (per-mode `fileRegex` and per-mode rules folder).** The two 🔴s are the **same blockers** as the Chat path (G-1, G-2). Net: **the CLI does not introduce new blockers** versus Chat. The CLI **adds** wins in headless scripting, hooks, skills, sessions, BYOK provider, and `COPILOT_HOME` portability; it **loses** the webview UI affordances entirely. +- **Headline finding (CLI-G-1 hook workaround):** Unlike Chat (which has no hook surface and therefore must enforce per-mode file restrictions via prose only), **the CLI can enforce `fileRegex`-equivalent rules via a `preToolUse` hook** on the `write` family. This is a strict CLI advantage over Chat for the single 🔴 blocker. (Filed as Q-035 for the reference-implementation work.) +- **Headline finding (BYOK — partial Q-030 resolution for the CLI):** The CLI honours `COPILOT_PROVIDER_BASE_URL` / `COPILOT_PROVIDER_TYPE` (openai/azure/anthropic) / `COPILOT_PROVIDER_API_KEY` / `COPILOT_MODEL`. Ollama via OpenAI-compat endpoint works. **The CLI removes the Chat-side G-13 (local-model) blocker** — relevant if the vault depends on local models. +- Open questions resolved or advanced: **Q-008 RESOLVED**, **Q-010 RESOLVED**, **Q-030 PARTIALLY RESOLVED** (CLI path). **Five new questions opened**: Q-031 (squad's `.copilot/mcp-config.json` non-standard location), Q-032 (repo `settings.json` 6-key allowlist constrains vault portability), Q-033 (no shared secret-substitution story between Chat `${input:…}` and CLI `${VAR}`), Q-034 (sub-agent depth/concurrency caps for nested orchestrator patterns), Q-035 (Windows reference implementation for `preToolUse` hook as `fileRegex` substitute). +- Phase 5 status badge in [`README.md`](README.md) advanced from ⬜ not-started to 🟡 in-progress (5a done; 5b pending). +- Phase 5b is now scoped to: (a) full MCP sectional treatment with squad-style vs canonical layouts side-by-side, (b) full hooks treatment (13 events × 3 hook types × 2 payload shapes; SSRF model; HTTPS-required cases), (c) full skills treatment, (d) exhaustive `@github/copilot-sdk` export catalogue, (e) the unified Gap Catalog with severities feeding Phase 6. +- **Phase-6 input ready early.** The mapping table in § 8 is structurally compatible with the Phase-4 Gap Catalog; Phase 6 can begin its merged matrix immediately rather than waiting for 5b. + +**Status** + +`accepted` + +--- + +## 2026-04-26 17:39 — Phase 5b-i (Copilot CLI MCP deep-dive + Hooks deep-dive incl. preToolUse/fileRegex verdict) complete + +**Context** + +Phase 5b-i was a narrowly scoped follow-up to 5a, populating only two sections of [`50-copilot-cli-research.md`](50-copilot-cli-research.md): § 9 **MCP Support** and § 10 **Hooks** (the headline section — the candidate `fileRegex` mitigation for CLI-G-1). Skills, Scripting/automation, full SDK exports, and the unified Gap Catalog remain deferred to Phase 5b-ii. + +**Decision** + +Populate the MCP and Hooks sections of [`50-copilot-cli-research.md`](50-copilot-cli-research.md) with primary-source findings cited to: + +- [`docs.github.com — add-mcp-servers (CLI how-to)`](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers) — canonical `mcpServers` schema, `/mcp add` form, server-management slashes. +- [`docs.github.com — Hooks configuration (reference)`](https://docs.github.com/en/copilot/reference/hooks-configuration) — input/output JSON for every event including the verbatim `preToolUse` payload + `permissionDecision` output contract. +- [`docs.github.com — Use hooks with Copilot CLI (tutorial)`](https://docs.github.com/en/copilot/tutorials/copilot-cli-hooks) — primary source for the `[Console]::In.ReadToEnd() | ConvertFrom-Json` PowerShell hook pattern and the cross-OS `bash`+`powershell` hook entry shape. +- [`docs.github.com — cli-command-reference`](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference) — full slash-command list, MCP server schema fields, hook event registry (camelCase + PascalCase aliases), repo-layer settings allowlist (six keys including `disableAllHooks` and `hooks`), `.vscode/mcp.json` → `.mcp.json` migration recipe. +- Active CLI bugs that bound the verdict: [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) (sub-agent bypass), [`#2540`](https://github.com/github/copilot-cli/issues/2540) (plugin hooks don't fire), [`#2893`](https://github.com/github/copilot-cli/issues/2893) (parallel-call race), [`#2013`](https://github.com/github/copilot-cli/issues/2013) (`modifiedArgs` ignored). + +Set the file's marker comment to ``. Advance the README Phase-5 badge to `🟡 in-progress (5a + 5b-i done — …; 5b-ii pending — Skills, Scripting/automation, full SDK surface, Gap Catalog)`. + +**Rationale** + +- Phase 5b-i's narrow scope was deliberate: the **`preToolUse`-as-`fileRegex`-substitute verdict** is the single highest-leverage finding remaining in the entire investigation because it determines whether the CLI path (Path-B) closes the only 🔴 blocker (G-1) shared with the Chat path (Path-A). Resolving it required (a) the full `preToolUse` payload schema, (b) the deny-output JSON contract, (c) a runnable Windows PowerShell reference, and (d) a survey of active bugs that bound the workaround. Splitting Skills / SDK / Gaps off into 5b-ii prevents the scope from sprawling and produces a polished verdict on the load-bearing question. +- The MCP section was bundled because it shares the same primary-doc surface (`cli-command-reference`) and resolves three open questions (Q-031 squad's non-canonical MCP location, Q-033 the Chat-vs-CLI secret-substitution fork, partial Q-032 on the repo-settings allowlist) that the Hooks section would otherwise have had to re-derive. + +**Consequences — Headline findings** + +- **Headline finding (verdict — `preToolUse` vs `fileRegex`):** **Yes-with-caveats.** The CLI's `preToolUse` hook **does** mechanically substitute for Roo's per-mode `fileRegex` for the **main agent on serial tool calls** — `toolName`, `toolArgs.path` (after JSON parse), and the `{permissionDecision:"deny",permissionDecisionReason}` output contract are all there, and a working Windows PowerShell reference is in [§ 10.4](50-copilot-cli-research.md#104-pretooluse-deep-dive--the-fileregex-substitute). **It does not** close the gap for `task`-dispatched sub-agents ([`#2392`](https://github.com/github/copilot-cli/issues/2392)), parallel tool calls ([`#2893`](https://github.com/github/copilot-cli/issues/2893)), plugin-shipped policies ([`#2540`](https://github.com/github/copilot-cli/issues/2540)), or write-path mutation ([`#2013`](https://github.com/github/copilot-cli/issues/2013)). **Net for the unified Gap Matrix:** G-1 stays 🔴 *blocker* on the Chat path (no hook surface) but downgrades to **🟠 *major*** on the CLI path. This is a meaningful Path-B advantage but **not a clean parity win** — the vault must accept the sub-agent caveat or restructure orchestrator flows to use `--agent` boot mode rather than `task` dispatch. +- **Headline finding (CLI MCP — schema fork):** CLI `mcp-config.json` uses **`mcpServers`** at top level; Chat `.vscode/mcp.json` uses **`servers`** + a top-level **`inputs`** array. Migration is a one-liner (`jq '{mcpServers: .servers}'`) but **secrets do not migrate** — see next finding. +- **Headline finding (CLI MCP — secrets model on Windows, resolves Q-033):** CLI uses **process-env substitution only** (`$VAR` / `${VAR}` / `${VAR:-default}`); there is **no** `${input:…}` Credential-Manager prompt as on the Chat side, and the OS keychain is reserved for the GitHub auth token. Vault recommendation: persist secrets via `[Environment]::SetEnvironmentVariable("KEY","val","User")` and let the same `${KEY}` resolve in both layers (Chat side via env-fallback, CLI side natively). **No shared secret-handling story exists between Chat and CLI** — same logical secret needs two configs. +- **Headline finding (CLI MCP — slash commands):** Full set documented: `/mcp [show|add|edit|delete|disable|enable|auth|reload] [SERVER-NAME]`, plus the non-interactive `copilot mcp [list|get|add|remove]` for shell automation. Hot-reload is supported (no session restart on add/edit). +- **Headline finding (Squad's `.copilot/mcp-config.json` — resolves Q-031):** Non-canonical. The CLI's documented project-scope MCP location is `.github/mcp.json` (or `.mcp.json`). Squad's pattern relies on the squad launcher implicitly setting `COPILOT_HOME`; bare `copilot` from a squad-shaped project would not load it. Vault should prefer `.github/mcp.json` for project scope and `~/.copilot/mcp-config.json` (via `COPILOT_HOME`) for the user/vault layer. +- **Headline finding (Hooks — registry):** **13 events** confirmed (`sessionStart`, `sessionEnd`, `userPromptSubmitted`, `preToolUse`, `postToolUse`, `postToolUseFailure`, `agentStop`, `subagentStart`, `subagentStop`, `preCompact`, `permissionRequest`, `errorOccurred`, `notification`) × **2 payload shapes** (camelCase native / PascalCase VS-Code-compatible with snake_case fields) × **2 hook types** (`command` and `prompt`). The Phase-5a stub claimed three hook types including `http`; **correction**: `http` hooks exist on the **Cloud agent** surface but **not** on the CLI — filed as Q-038 for SDK confirmation. +- **Headline finding (`disableAllHooks` kill-switch — partial Q-032):** Honoured at both user and repo layers (`disableAllHooks` and `hooks` are 2 of the 6 keys the repo-layer allowlist accepts). Vault **can** ship per-project hook policy via committed `.github/copilot/settings.json` or `.github/hooks/*.json`. Safety caveat: the kill-switch is a committed file, so anyone with write access can disable enforcement with one boolean — gate behind branch protection for policy-critical environments. +- Open questions resolved: **Q-031** (squad MCP location), **Q-033** (secret-substitution fork). Partially resolved: **Q-032** (hooks-allowlist scope confirmed; tool-allowlist scope still open), **Q-035** (`preToolUse` mechanism + verdict landed; Windows latency / env / sub-agent bypass concerns split into Q-039 / Q-040 / kept under Q-035 verdict). New questions opened: **Q-036** (user-scope hook discovery — `~/.copilot/hooks/*.json` vs inline `config.json`), **Q-037** (active-agent name not in hook payload), **Q-038** (CLI hook-type set: `command` + `prompt` only, no `http`?), **Q-039** (`pwsh` cold-start latency on user box), **Q-040** (`${env:VAR}` expansion in hook entry `env` map). +- **Phase 5b-ii is now scoped to:** Skills (§ 11), Scripting/automation deep-dive (§ 3.4 expansion), full `@github/copilot-sdk` export catalogue (§ 7), and the unified CLI Gap Catalog (§ 12) — all of which can now reference the resolved Hooks/MCP findings rather than re-derive them. + +**Status** + +`accepted` + +--- + +## 2026-04-26 17:50 — Phase 5b-ii-A (Copilot CLI Skills + Scripting/automation incl. Roo `apps/cli` event-emitter comparison) complete + +**Context** + +Phase 5b-ii-A was a narrowly scoped follow-up to 5b-i, populating only two sections of [`50-copilot-cli-research.md`](50-copilot-cli-research.md): § 11 **Skills** and the new § 12 **Scripting / automation** (the existing Limits/Gap Catalog stub was renumbered to § 13 without content changes). The full `@github/copilot-sdk` export catalogue and the unified CLI Gap Catalog remain deferred to Phase 5b-ii-B. + +**Decision** + +Populate the Skills and Scripting/automation sections of [`50-copilot-cli-research.md`](50-copilot-cli-research.md) with primary-source findings cited to: + +- [`docs.github.com — Adding agent skills for Copilot CLI`](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills) — canonical SKILL.md schema, storage paths, invocation model, `/skills` slash family. +- [`docs.github.com — Quickstart for automating with Copilot CLI`](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/quickstart) and [`run-cli-programmatically`](https://docs.github.com/en/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically) — full headless-flag catalogue and CI examples. +- [`docs.github.com — CLI command reference § Command-line options`](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#command-line-options) — flag verification (and OTel statement). +- [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) — open feature request **confirming the CLI does not yet support `--output-format json` / `stream-json`** (Phase-5a § 3.4 stub overstated this; corrected in § 12.1). +- [`apps/cli/src/agent/json-event-emitter.ts`](../../../apps/cli/src/agent/json-event-emitter.ts) — Roo's CLI event-stream implementation read in full for the side-by-side in § 12.6. +- [`../squad/.copilot/skills/`](../../../../squad/.copilot/skills) directory listing — 23 SKILL.md files (the brief estimated 24; actual count is 23). +- [`../squad/README.md` § Watch Mode](../../../../squad/README.md) — Ralph daemon primitives + the nuance that Ralph's default `--agent-cmd "gh copilot"` invokes the **legacy** CLI extension, not `@github/copilot`. + +Set the file's marker comment to ``. Advance the README Phase-5 badge accordingly. + +**Rationale** + +Phase 5b-ii-A's narrow scope was deliberate: Skills and Scripting/automation are the two surfaces that determine whether the CLI path can carry the vault's *automation* workload — not just interactive coding. Resolving them together let the same primary-doc surface (the [add-skills](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills) and [programmatic reference](https://docs.github.com/en/copilot/reference/copilot-cli-reference/cli-programmatic-reference) docs) be cited cleanly, and produced the **single most consequential correction** in the investigation so far: the structured-event-stream gap (G-6) that the Phase-5a stub had hidden. + +**Consequences — Headline findings** + +- **Headline finding (Skills — what they are):** A skill is a *directory* (not a file) with `SKILL.md` + arbitrary sibling resources (scripts, samples). The whole directory is loaded into the agent's context when the skill activates. Skills implement the open [Agent Skills standard](https://agentskills.io/) so a Copilot-flavoured `SKILL.md` is also discoverable by Claude Code, Cursor, Gemini CLI, Codex CLI — a rare cross-tool surface for this investigation. +- **Headline finding (Skills — frontmatter):** Required `name` (slash-command name) + `description` (autonomous-trigger string — must be specific or skills silently fail to fire per [`copilot-cli#978`](https://github.com/github/copilot-cli/issues/978)). Optional `license` + `allowed-tools`. **`user-invocable` and `disable-model-invocation` are NOT documented for the Copilot CLI** even though the cross-tool standard defines them — silently ignored (filed as Q-041). +- **Headline finding (Skills — storage):** Scope tiers `~/.copilot/skills/`, `~/.claude/skills/`, `~/.agents/skills/` (user) and `.github/skills/`, `.claude/skills/`, `.agents/skills/` (project). Project beats user; plugins lowest. Squad's `.copilot/skills/` (23 files at investigation time) is **non-canonical** and works only via launcher-set `COPILOT_HOME` — same Q-031 pattern as MCP. +- **Headline finding (Skills — invocation):** Three modes: autonomous (description-driven), explicit `/` slash in prompt, REPL `/skills [list|info|reload|add|remove]`. Autonomous mode is unreliable in practice ([`#978`](https://github.com/github/copilot-cli/issues/978)) — the explicit slash is the production-reliable path. +- **Headline finding (Skills — vs Roo):** Strict additive capability. The closest Roo analogues (`.roo/rules-/`, orchestrator `new_task`, mode `customInstructions`) each cover only part of what a skill does. Skills are dynamically loaded by description, are reusable across agents, and can ship executable resources. Net for Path-B (CLI) playbook: skills are the natural home for the procedural memory currently scattered across Roo rules + custom instructions. +- **Headline finding (Skills — Windows-first concern):** Official examples are Bash-first; Windows users must dual-ship `.sh` + `.ps1` (squad's `distributed-mesh/` skill is the working pattern) and pre-approve both `bash` and `shell` in `allowed-tools` to avoid prompt-storms. +- **Headline finding (Scripting — corrected misclaim):** **The CLI does NOT yet emit structured JSON events.** Phase-5a § 3.4 claimed `--output-format=text|json` exists; verified-against-canonical: it does not. [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) is the open feature request. Until shipped, automation requiring structured events must use `@github/copilot-sdk` (streaming-events channel). **This adds a new 🟠 G-6 gap to the CLI catalog** that Phase 6 must integrate. +- **Headline finding (Scripting — flag set):** Full verified catalogue in § 12.2 — 22 flags including `-p`, `-s`, `--no-ask-user`, `--allow-tool=PATTERN` (the workhorse), `--model`, `--agent`, `--config-dir`, `--resume`, `--share[-gist]`, `--additional-mcp-config`, `--cwd`, `--no-color`, `--mode=plan|interactive|autopilot`, `--max-autopilot-continues`. Permission patterns use `Kind(arg)` form: `shell(git:*)`, `write(./src/**)`, `url(github.com)`. Deny wins over allow. Exit codes: `0` success / non-zero overloaded (G-7, filed as Q-043). +- **Headline finding (Scripting — Ralph daemon):** Squad's Ralph proves the CLI does not need its own daemon mode — process supervision (Ralph here, but also `pm2`/Scheduled Tasks/Actions cron) is sufficient when the CLI is cheap to spawn and respects `--no-ask-user`. **Important nuance: Ralph's default `--agent-cmd "gh copilot"` invokes the LEGACY CLI extension; vault adoption must override to `--agent-cmd "copilot"`** to use the agentic `@github/copilot` binary that is the actual migration target. +- **Headline finding (Scripting — Roo `apps/cli` comparison):** Roo's `apps/cli` is architecturally distinct (extension-host harness with rich NDJSON event stream via [`json-event-emitter.ts`](../../../apps/cli/src/agent/json-event-emitter.ts) — `system:init` / `assistant` / `thinking` / `tool_use` / `tool_result` / `result` / `cost`, with delta tracking, schema versioning, sequence guarantees). Copilot CLI today emits plain text. **Migration implication:** any vault automation parsing Roo's NDJSON must either drop down to the SDK or accept text-only output and lose per-tool/per-token telemetry. Single largest CLI scripting gap versus Roo. +- **Headline finding (Scripting — OTel):** CLI supports OpenTelemetry trace+metric export via standard OTLP env vars (per CLI command reference). Strict win versus Roo's `apps/cli` (no OTel) and partial mitigation for G-6 if aggregate metrics suffice. +- **Open questions** added: **Q-041** (CLI's silent ignore of `user-invocable`/`disable-model-invocation`), **Q-042** (track [`#52`](https://github.com/github/copilot-cli/issues/52) until structured output ships), **Q-043** (granular exit codes). No prior open questions resolved by this sub-phase (the resolutions in 5a/5b-i remain). +- **Phase 5b-ii-B is now scoped to:** the exhaustive `@github/copilot-sdk` export catalogue (§ 7 expansion) + the unified CLI Gap Catalog (§ 13) that integrates G-1..G-7 with the headline findings from 5a, 5b-i, and 5b-ii-A — with G-6 (no structured event stream) and G-7 (overloaded exit codes) as the new entries this sub-phase contributed. + +**Status** + +`accepted` + +--- + +## 2026-04-26 17:58 — Phase 5b-ii-B-1: `@github/copilot-sdk` exports catalogued; Path-D embeddability = 🟡 with shim + +**Context** + +Phase 5b-ii-B-1 replaced the § 7 SDK headline stub in [`50-copilot-cli-research.md`](50-copilot-cli-research.md#7-sdk-githubcopilot-sdk--full-export-catalogue-phase-5b-ii-b-1) with a full export catalogue of `@github/copilot-sdk@0.3.0`, cross-referenced against Squad's actual SDK consumption (`squad-sdk/src/adapter/client.ts`, `adapter/types.ts`, `tools/index.ts`, `build/bundle.ts`, `squad-cli/src/cli-entry.ts`). Goal: produce a defensible **Path-D (vault-as-VSIX) embeddability verdict** and finalise the SDK surface knowledge needed for Phase 6 / Phase 7 path scoring. CLI Gap Catalog (5b-ii-B-2) deliberately deferred. + +**Decision** + +Record the **Path-D embeddability verdict** as **🟡 embeddable with shim** and adopt it as a Phase-7 input. + +**Rationale — Headline findings** + +- **Headline (identity):** `@github/copilot-sdk` is **MIT, public preview (0.x)**, v0.3.0 at access, 54 versions in ~5 months, 134 dependents, runtime deps = 3 (lean), Node 20+. The SDK is a **transport wrapper** over the CLI binary (JSON-RPC via `vscode-jsonrpc`); **it contains no model client of its own**. This anchors all downstream architecture decisions. +- **Headline (top exports):** `CopilotClient` (lifecycle + session admin + `listModels`/`ping`/`getStatus`/`getAuthStatus`), `CopilotSession` (`send`/`sendAndWait`/`abort`/`getMessages`/typed `on`/`disconnect`), `defineTool` (Zod-typed custom tools), `approveAll` (test helper), in-process `SessionHooks` (`onPreToolUse`/`onPostToolUse`/`onUserPromptSubmitted`/`onSessionStart`/`onSessionEnd`/`onErrorOccurred`), `ProviderConfig` (BYOK: openai/azure/anthropic + env-var fallback), elicitation/user-input/permission handlers. Event types are dotted (`assistant.message_delta`, `tool.execution_start`, `session.shutdown`). +- **Headline (Squad's actual usage corrects 5a stub):** Squad has **exactly one** value-level SDK import — `CopilotClient` in `adapter/client.ts:10`. Squad's `defineTool` at `tools/index.ts:116` is a **re-implementation, not a re-export**; the stub claim that Squad uses `defineTool` from the SDK was wrong. Squad insulates the rest of its codebase via `Squad*` mirror types in `adapter/types.ts` (explicit comment: *"All Squad code should import types from this adapter layer, never directly from the Copilot SDK."*). Squad pin is `^0.1.32` — three minor versions behind current `0.3.0`; drift absorbed by `as Parameters[N]` casts. +- **Headline (Squad as cautionary tale for SDK consumers):** Squad ships a runtime ESM patcher ([`squad-cli/src/cli-entry.ts:25`](../squad/packages/squad-cli/src/cli-entry.ts:25)) for `@github/copilot-sdk@0.1.32`'s broken `vscode-jsonrpc/node` import, plus a `doctor` command that re-validates the patch. This is the cost of consuming a 0.x SDK with monthly minor bumps. Vault automation must budget for similar maintenance. +- **Headline (BYOK reaffirmed):** SDK supports the same `provider: { type: "openai"|"azure"|"anthropic", baseUrl, apiKey }` configuration as the CLI's env vars; Ollama-via-OpenAI-compat works. Resolves the SDK side of Q-030 in addition to the CLI side already resolved in 5a § 7. +- **Headline (Path-D verdict — 🟡 embeddable with shim):** SDK can run in the **VS Code extension host** (full Node, supports `child_process` and `vscode-jsonrpc`). It **cannot** run in webviews (sandboxed, no `child_process`). A Path-D VSIX therefore must (a) require user-installed `@github/copilot` CLI on `PATH` or bundle the CLI in the VSIX (size + signing concerns), (b) keep all SDK calls in the extension-host process, (c) accept process-spawn cost per session, (d) re-architect Roo's webview-driven UX as either a chat-participant UI or an extension-host ↔ webview `postMessage` bridge. **This nullifies the "trivially embed Squad" hope from Q-010** — both Squad and the SDK are structurally CLI-driver libraries, not embeddable model clients. Path D remains feasible but is *not* a free win; cost is ~1 engineer-month of extension-host harness work plus ongoing 0.x SDK maintenance. +- **Headline (license/versioning risk):** MIT ✅; preview 0.x carries breaking-change risk per minor (e.g., `autoRestart` removal already happened). Mitigation patterns observable in Squad: adapter-mirror types, `as Parameters[N]` casts, runtime patcher, doctor command. Vault should adopt the same pattern if it depends on the SDK directly. + +**Consequences** + +- Path A (Chat-only) and Path B (CLI-only) are unaffected — the SDK is optional for them. +- Path C (Squad-mediated) is reaffirmed as feasible but inherits the SDK's 0.x churn cost. +- Path D (vault-as-VSIX) is now **scored 🟡 (not 🟢)** — it works but is not architecturally trivial; Phase 7 must compare its cost-to-value against Path A/B. +- **New open questions opened: Q-044, Q-045, Q-046** (see [`99-open-questions.md`](99-open-questions.md)). +- Resolves: **Q-010 sharpened** (Squad has zero `vscode.lm` deps **and** the SDK it depends on is itself a CLI-driver, so embedding requires extension-host shim). **Q-038 partially advanced** (SDK exposes `SessionHooks` interface — six lifecycle callbacks, `command` and `prompt` are file-hook-only; `http` not present at the SDK layer either, so the CLI most likely lacks it as well). Phase-5a stub claim that Squad uses SDK's `defineTool` corrected. +- Phase 5b-ii-B-2 (CLI Gap Catalog) remains the only outstanding sub-phase. + +**Status** + +`accepted` + +--- + +## 2026-04-26 18:05 — Phase 5 closed; ready for Phase 6 synthesis + +**Context** + +Phase 5b-ii-B-2 was the only outstanding sub-phase of Copilot CLI research. With the unified CLI Gap Catalog now populated in [`50-copilot-cli-research.md` § 13](50-copilot-cli-research.md#13-limits--known-gaps-relative-to-roo-cli-gap-catalog--phase-5b-ii-b-2), all of Phases 1–5 (inventory, Squad cross-ref, Chat research, CLI research) are complete. The investigation can now move to Phase 6 (cross-cutting gap analysis) with both Chat and CLI Gap Catalogs in matching G-/W- + CG-/CW- format ready to merge. + +**Decision** + +Flip Phase 5 to ✅ complete. Proceed to Phase 6 next. + +**Rationale — CG-/CW- tally summary** + +- **Inherited Chat gaps under CLI severities (Part A, 14 IDs):** + - 🟠 major (4): G-1 (demoted from 🔴), G-2, G-5 (worse on CLI), G-9 (better-but-still-major elsewhere — minor here). + - 🟡 minor (5): G-4, G-7, G-12, G-14, G-9 (CLI-side rating). + - ✅ closed-on-CLI (4): G-3 (N/A), G-8, G-11, G-13. + - ✅ better (2): G-6, G-10. +- **CLI-specific gaps (Part B, CG-1…CG-15, 15 IDs):** + - 🟠 major (5): CG-1 (webview-UI loss), CG-4 (repo-allowlist scope), CG-7 (no structured output), CG-8 (SDK churn), CG-11 (sub-agent hook bypass). + - 🟠 (Path-C-only): CG-12 (Squad alpha). + - 🟡 minor (9): CG-2, CG-3, CG-5, CG-6, CG-9, CG-10, CG-13, CG-14, CG-15. + - 🔴 blockers: **0** — every CLI-specific gap has a documented workaround. +- **CLI-specific wins (Part C, CW-1…CW-12, 12 IDs):** all 🟢. Match Chat's W-1…W-12 count; CW-1/CW-2/CW-3/CW-6 close Chat-side gaps outright (G-1 mitigation, G-13, observability, G-11). + +**Net headline:** CLI carries **0 × 🔴 + 9 × 🟠 + 14 × 🟡** vs Chat's **1 × 🔴 + ~4 × 🟠 + ~6 × 🟡**. CLI eliminates Chat's lone blocker (with the CG-11 sub-agent caveat) and three of Chat's four majors, at the cost of four new CLI-only majors centred on observability, SDK churn, and the sub-agent hook bypass. + +**Consequences** + +- Phase 5 marked ✅ complete in [`README.md`](README.md); [`50-copilot-cli-research.md`](50-copilot-cli-research.md) front-matter flipped to `status: complete`; final marker comment updated. +- Phase 6 (gap analysis) is now unblocked and is the next subtask: it should merge the Chat G-/W- catalog (40 § 8) with the CLI G-/W-/CG-/CW- catalog (50 § 13) into a single matrix, then score each row against the vault's actual usage to produce per-axis path recommendations. +- **Top 3 upstream risks tracked:** [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) (sub-agent hook bypass — CG-11), [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52) (structured output — CG-7 / Q-042), Q-039 (empirical `pwsh` cold-start latency — CG-6). +- **Resolved questions this round:** Q-031, Q-033 (already resolved earlier in Phase 5b-i, now formally cited in the CLI Gap Catalog); Q-035 stays partially-resolved with explicit caveats now codified as CG-11 / CG-13 / CG-14 / CG-15. +- **New open questions:** Q-047 (severity-tally consistency check vs vault's actual `fileRegex` usage in Phase 6) — see [`99-open-questions.md`](99-open-questions.md). +- The Phase-5 file template's original "preview" Gap Catalog placeholder has been replaced in full; § 13 is now the canonical source. + +**Status** + +`accepted` + +--- + +## 2026-04-26 18:16 — Phase 6 (unified gap analysis) complete; ready for path-selection synthesis (Phase 7) + +**Context** + +Phase 6 was the synthesis phase that merged the Chat-side Gap Catalog (G-1..G-14 + W-1..W-12, from [`40-copilot-chat-research.md` § Limits/Known Gaps](40-copilot-chat-research.md#limits--known-gaps)) and the CLI-side Gap Catalog (CG-1..CG-15 + CW-1..CW-12, from [`50-copilot-cli-research.md` § 13](50-copilot-cli-research.md#13-limits--known-gaps-relative-to-roo-cli-gap-catalog--phase-5b-ii-b-2)) into a single feature-axis matrix. No new web research was performed; all rows trace back to citations established in Phases 1–5. The Squad column was framed as **"what Squad adds on top of the CLI"** (per the task brief), not as a third independent path. + +**Decision** + +Populate [`60-gap-analysis.md`](60-gap-analysis.md) with: methodology header (dual-severity convention `Chat / CLI ` for divergent rows; single-icon when both paths agree), 12 grouped sections (B.1 modes/agents, B.2 tool restrictions, B.3 prompts/rules, B.4 MCP, B.5 orchestrator, B.6 native tools, B.7 webview, B.8 CLI/scripting, B.9 settings/portability, B.10 model selection, B.11 sessions, B.12 approval/safety) totalling ~70 matrix rows with columns `Roo feature | Chat | CLI | Squad | Gap severity | Workaround | Notes`, severity tally table (§ C), top-10 most-important rows (§ D), Squad-column interpretation note (§ E), and Phase 7/8 handoff (§ F) including two newly opened questions. Flip front-matter `status: complete`, populate `sources:` with the 6 input files, advance README Phase-6 badge to ✅. + +**Rationale — severity tally (synthesis output)** + +- **Chat path:** **2 × 🔴 blocker · 8 × 🟠 major · 12 × 🟡 minor · 22 × ✅ parity · 4 × ➕ additive.** Blockers: G-1 (per-mode `fileRegex` edit restrictions) and G-2 (per-mode rules folder `.roo/rules-/`) — both are doc-prose-workaroundable but not first-class. +- **CLI path:** **0 × 🔴 blocker · 7 × 🟠 major · 11 × 🟡 minor · 27 × ✅ parity · 8 × ➕ additive.** The CLI eliminates Chat's lone hard-blocker via the `preToolUse` hook (G-1 → 🟠 with the CG-11 sub-agent caveat from [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392)) and downgrades G-13 (local models) and G-11 (cloud-agent reuse) to ✅ via `COPILOT_PROVIDER_*` BYOK env vars and shareable sessions. Net 4 majors are CLI-specific: CG-1 (webview-UI loss), CG-7 (no structured event stream — [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52)), CG-8 (SDK 0.x churn), CG-11 (sub-agent hook bypass). +- **Squad overlay (additive only):** **+7 × ➕ wins** when layered on the CLI — parallel fan-out (`fleet`/`wave`), persistent named agents from a casting registry, Ralph daemon for watch-mode automation, committed `.squad/` markdown state, batch sub-agent dispatch with concurrency caps, and a typed adapter layer that insulates from SDK churn. Squad introduces zero new gaps but inherits all CLI gaps + adds CG-12 (alpha v0.9.1 maturity risk) when chosen as the orchestration layer. + +**Headline finding (the 3 path-determining rows)** + +1. **B.2 / G-1 (per-mode `fileRegex`)** — Chat 🔴 (no hook surface, prose-only enforcement); CLI 🟠 (preToolUse closes it for boot-agent serial calls; sub-agent dispatch via `task` still bypasses per [`#2392`](https://github.com/github/copilot-cli/issues/2392)). **This row alone tilts the choice toward the CLI for any vault that depends on edit-scope safety.** +2. **B.7 / CG-1 (webview UI loss on CLI)** — Chat ✅ (full webview parity via VS Code chat panel); CLI 🟠 (terminal-only, no settings UI, no diff preview, no MCP marketplace). **This row alone tilts the choice back toward Chat for any user who values the in-IDE GUI.** +3. **B.8 / CW-3 (headless scripting + hooks + sessions)** — Chat ➕ (chat history, no headless mode); CLI ➕➕ (`--no-ask-user`, `--allow-tool=PATTERN`, `--share[-gist]`, `COPILOT_HOME` portability, OTel export, full hook suite). **The CLI is strictly required for any automation-heavy workload regardless of the Chat-vs-CLI primary choice — it is realistically a both-paths story.** + +**Resolved / advanced questions** — None resolved cleanly by Phase 6 (no new evidence, only synthesis); **Q-047** advanced (the severity-tally consistency check is now embedded as the dual-severity convention in B.2 row G-1 and is owned by the user's Phase-7 vault audit, not by further documentation work). + +**New questions opened (synthesis-discovered)** + +- **Q-048** — `AGENTS.local.md` gitignored-personal-overrides convention (added to [`99-open-questions.md`](99-open-questions.md) and surfaced in [`60-gap-analysis.md` § F.4](60-gap-analysis.md)). +- **Q-049** — Roo's `update_todo_list` re-injection has no documented Copilot equivalent (added to [`99-open-questions.md`](99-open-questions.md) and surfaced in [`60-gap-analysis.md` § F.4](60-gap-analysis.md)). + +**Consequences** + +- Phase 7 (migration paths) is unblocked. The matrix's three path-determining rows + severity tallies + Squad-as-overlay framing collectively produce a structured path-scoring input: Path-A (Chat-only) carries 2 blockers; Path-B (CLI-only) carries 0 blockers but loses the webview UX; Path-C (Chat + CLI hybrid, optionally with Squad overlay) carries 0 blockers and recovers the UX at the cost of dual-config maintenance. Path-D (vault-as-VSIX) re-enters as the only architecture that closes G-1/G-2 cleanly without the CLI's CG-11 caveat — at the cost flagged in Q-046. +- Phase 8 (playbook) inherits the matrix as its per-feature migration checklist; Q-048 and Q-049 are new playbook concerns; the existing Q-026 (multi-profile `mcp.json` symlink helper) and Q-029 (sessions portability) join them as concrete script-writing tasks. +- README Phase-6 badge flipped from ⬜ not-started to ✅ complete. Overall index status remains "Phases 1–6 done; Phases 7–9 remain" — README header `status: in-progress` is appropriate until Phase 9. +- No row was deferred (the brief allowed `⏭ deferred` if the matrix exceeded 100 rows; final count is ~70, so all rows landed in-band). + +**Status** + +`accepted` + +--- + +## 2026-04-26 18:27 — Phase 7 (migration paths) complete; **recommendation = Path Hybrid (Chat + CLI)** + +**Context** + +Phase 7 was the path-selection synthesis phase. It scored the four candidate paths from [`00-plan.md`](00-plan.md) (A Chat-only, B CLI-only, C CLI+Squad, D Vault-as-VSIX) plus a Hybrid (Chat + CLI sharing `.agent.md`/`AGENTS.md`) against an 8-criterion weighted framework derived from the user's documented context (Windows 11 + 17-mode vault + IDE-centric + automation-aware) and the unified Gap Matrix in [`60-gap-analysis.md`](60-gap-analysis.md). No new web research was performed; all citations resolve to Phases 1–6. + +**Decision** + +**Adopt Path Hybrid as the primary migration path.** Use Copilot Chat for interactive IDE work + Copilot CLI for automation, hook-based `fileRegex` policy enforcement, and BYOK. Share `.agent.md` files via symlink between `.github/agents/` and `~/.copilot/agents/`; share one `AGENTS.md` per project read natively by both surfaces; generate the two MCP file shapes from one canonical source (Q-050 owns the choice) via a Phase-8 converter. + +**Rationale — score table** + +| Criterion | Wt | A | B | C | D | **Hybrid** | +|---|---:|---:|---:|---:|---:|---:| +| C1 Capability fidelity | 30% | 2 | 4 | 4 | 5 | **4** | +| C2 Effort | 20% | 4 | 3 | 2 | 1 | **3** | +| C3 Operational risk | 15% | 4 | 3 | 2 | 2 | **3** | +| C4 Day-to-day UX | 10% | 5 | 2 | 2 | 5 | **4** | +| C5 Automation / CI | 10% | 1 | 5 | 5 | 3 | **5** | +| C6 Vault portability | 5% | 3 | 5 | 4 | 4 | **5** | +| C7 Reversibility | 5% | 4 | 5 | 3 | 2 | **5** | +| C8 Cost | 5% | 3 | 5 | 5 | 3 | **5** | +| **Weighted total** | **100%** | **3.10** | **3.70** | **3.20** | **3.25** | **3.90** | + +Three-bullet justification: + +- **Hybrid scores highest (3.90)** and is the only path with no score below 3 on any criterion. It closes G-1 where it matters (the CLI surface enforces `preToolUse` for the vault's regex-bound modes — architect, translate, docs-extractor — confirmed in [`20 § Global Settings`](20-roo-vault-inventory.md)) without forcing the user out of the IDE for the modes that don't need it. +- **Effort is bounded** at 1–2 weeks first-project / <1 day per new project — comparable to Path A alone, materially less than Path C (2–4 weeks + alpha tax) or Path D (~1 engineer-month per [50 § 7](50-copilot-cli-research.md#7-sdk-githubcopilot-sdk--full-export-catalogue-phase-5b-ii-b-1) verdict). +- **Maximum reversibility** because `.agent.md` and `AGENTS.md` are cross-tool standards (Claude Code, Cursor, Codex, Gemini CLI all read at least one); only the MCP layer genuinely duplicates per the [CG-3 schema fork](50-copilot-cli-research.md#13-limits--known-gaps-relative-to-roo-cli-gap-catalog--phase-5b-ii-b-2). + +**Conditions that would flip the recommendation** (top three from § 4.2): + +1. If the vault's `fileRegex` audit (Q-047) returns zero rules → Path A (3.10 → 3.70) becomes acceptable; drop the CLI side if also no automation. +2. If user has no automation/CI/cron workflows planned → Path A becomes acceptable (C5's weight is wasted in Hybrid). +3. If the user has a demonstrated parallel-orchestration workload → escalate to Path C (Hybrid + Squad on the CLI side). + +**Consequences** + +- Phase 8 (migration playbook) is unblocked. Primary scope: Path Hybrid; Appendix scope: Path B-only mapping for the user who later prefers terminal-first workflows. Detailed hand-off in [`70-migration-paths.md` § 7](70-migration-paths.md). +- Phasing recommendation in [`70-migration-paths.md` § 4.4`](70-migration-paths.md): Stage 1 (week 1) Path A scaffold; Stage 2 (week 2) add CLI for the gaps; Stage 3 (later, conditional) escalate to C or D only if specific triggers fire. +- Path C and Path D are explicitly **NOT recommended** as starting points for the user's current vault. Both remain documented as Stage-3 escalations. +- Two new open questions surfaced: **Q-050** (canonical-source for dual-format MCP under Hybrid), **Q-051** (`AGENTS.md` ↔ `AGENTS.local.md` dual-surface read order). Existing Q-047 (`fileRegex` audit), Q-030 (vault BYOK usage), Q-024 (`*.toolsets.jsonc` Settings Sync) flagged as "resolve before Phase 8 execution". +- README Phase-7 badge flipped from ⬜ not-started to ✅ complete. Phase-8 status remains ⬜ not-started. +- Ready for [`80-migration-playbook.md`](80-migration-playbook.md) to begin. + +**Status** + +`accepted` + +--- + +## 2026-04-26 18:35 — Phase 8a complete: shared assets + Chat-side playbook delivered + +**Context** + +Phase 7 ([`70-migration-paths.md`](70-migration-paths.md)) recommended **Path Hybrid** (Chat + CLI, weighted score 3.90). Phase 8 was split into 8a (shared core + Chat side) and 8b (CLI side + MCP schema fork + automation + validation + rollback) so the user can begin Stage-1 (Chat scaffold) work immediately while the more involved CLI hook authoring is queued for a separate subtask. + +**Decision** + +Populated the first half of [`80-migration-playbook.md`](80-migration-playbook.md) with six sections: + +- **§ 0 — Overview & scope.** Path Hybrid context, architecture sketch (shared `.agent.md` + `AGENTS.md`; MCP duplicated per CG-3), full map of which sections are 8a vs 8b vs appendix, ✅/⏭/❌/⚠ badge convention. +- **§ 1 — Pre-migration checklist.** 7 numbered steps the user runs before touching config: vault `fileRegex` audit (Q-047 with `Select-String` command), canonical MCP source decision (Q-050 with three options + recommendation = "Chat-as-truth + jq generator"), subscription tier verification (table mapping features to tiers), `node -v` verification, dated backup script, Roo-extension disable (don't uninstall), upstream-issue watch list (`copilot-cli#52`, `#2392`, `vscode#251515`, `#251603`). +- **§ 2 — Shared assets.** Three sub-sections covering files that work on both surfaces: § 2.1 `AGENTS.md` (cross-tool standard, with `AGENTS.local.md` verification recipe per Q-051); § 2.2 `.agent.md` schema (canonical frontmatter, fully-worked architect-mode conversion side-by-side, asymmetric user-scope symlink helper, complete Roo→`.agent.md` field-mapping table); § 2.3 `.github/instructions/*.instructions.md` with `applyTo` glob (frontmatter schema, migration script, per-mode rules-folder ⏭ deferred to 8b). +- **§ 3 — Chat-side configuration.** Four sub-sections: § 3.1 `.vscode/mcp.json` (workspace, side-by-side conversion + `${input:…}` semantics + commit safety); § 3.2 `%APPDATA%\Code\User\mcp.json` (user/profile, profile-aware path note, fully-worked target with 4 enabled vault servers); § 3.3 `*.toolsets.jsonc` (G-3 workaround = inline `tools:` per agent, optional user-scope toolset example, Q-024 sync caveat); § 3.4 `.github/copilot-instructions.md` decision matrix vs `AGENTS.md` vs `.instructions.md`. +- **§ 4 — 17-mode mapping table.** One row per vault mode (slug, target tools allowlist, `Has fileRegex?`, target filename, notes). Best-effort tools column derived from [20 § Global Settings](20-roo-vault-inventory.md); user re-runs § 1 step 1 to confirm. Hook coverage list explicit at the bottom: 4 modes (`docs-writer`, `translate`, `docs-extractor`, `architect`) need Phase 8b `preToolUse` enforcement. +- **§ 5 — Step-by-step Phase 8a execution.** 8 numbered runnable PowerShell commands (directory creation, mode-loop sketch, AGENTS.md, rules conversion, MCP rewrite, user MCP, reload + verify, first-run secret prompt validation). +- **§ 6 — Hand-off to Phase 8b.** Cross-references the 4 hook-required rows from § 4, the Q-050 generator recommendation, and the pending Q-047/Q-051 user-executable verifications. + +CLI-specific sections (§ 7–§ 12 + Appendix B) left as stubs in § 0's section map with `⏭ deferred to 8b` markers. File status remains `in-progress` per the brief; marker comment `` added to the file head. + +**Rationale** + +- **Splitting 8 into 8a/8b unlocks parallel work** — the user can start Stage-1 (Chat scaffold per [`70 § 4.4`](70-migration-paths.md#-44--phasing-suggestion)) immediately with everything 8a delivers; 8b can be authored as a separate subtask without blocking. +- **Synthesis only — no web research required.** Every claim in 8a is sourced from existing memory files (10/20/40/60/70/99); inline cross-references (with section anchors) make the audit trail explicit. +- **Directly executable bias.** PowerShell commands, frontmatter snippets, side-by-side YAML→Markdown conversions, and the 4 enabled-MCP-server target file are paste-ready. The architect-mode worked example doubles as a template for the remaining 16 modes. +- **17-mode table is skeleton-with-audit-command, not fabricated values.** Where `tools:` or `fileRegex` data is uncertain without re-running the audit, the column is filled best-effort from [20 § Global Settings](20-roo-vault-inventory.md) and § 1 step 1 provides the exact `Select-String` command for user confirmation. + +**Consequences** + +- The user can begin Stage-1 (per [`70 § 4.4`](70-migration-paths.md#-44--phasing-suggestion)) using only the 8a sections. +- Phase 8b is unblocked and scoped: hook coverage = 4 modes (named in § 4); MCP generator design = Chat-as-truth + `jq` (per § 1 step 2); CLI mirror config = parallel to § 3 with the schema-fork rename. +- README's Phase-8 badge flipped from ⬜ not-started to 🟡 in-progress (8a complete). +- Two new questions surfaced: **Q-052** (precise group→tools expansion table for non-`read`/`edit`/`mcp` Roo groups) and **Q-053** (whether `.agent.md` `agents:` allowlist accepts emoji-prefixed display names or requires the kebab-case slug). See [`99-open-questions.md`](99-open-questions.md). +- The pending Q-047 audit (vault `fileRegex` blast radius) and Q-051 dual-surface verification of `AGENTS.local.md` are explicitly hand-listed in § 6 as user-executable prerequisites for 8b. + +**Status** + +`accepted` + +--- + +## 2026-04-26 18:45 — Phase 8b-i: Chat-as-truth MCP generator chosen (Q-050) and CG-11 sub-agent bypass mitigation locked in + +**Context** + +Phase 8a left two cliff-edges to resolve before Stage-2 (CLI rollout) could proceed: (1) Q-050 — the dual-format MCP fork (Chat `servers:` vs CLI `mcpServers:`, CG-3) needed a canonical-source decision so users wouldn't have to hand-edit two files; (2) CG-11 — the sub-agent `preToolUse` bypass bug ([`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392)) threatened to re-escalate G-1 from 🟠 back to 🔴 on the CLI path because the vault's orchestrator pattern dispatches frequently. Phase 8b-i had to commit to a stance on both before authoring §§ 7–9 of [`80-migration-playbook.md`](80-migration-playbook.md). + +**Decision** + +1. **Q-050 — Chat (`.vscode/mcp.json`) is the source of truth; CLI `mcp-config.json` is generated.** Adopt option (a) from § 1 step 2 of the playbook. Ship a PowerShell generator script ([`80 § 9.1`](80-migration-playbook.md#-91--generator-script--scriptsgenerate-cli-mcppspowershell)) that: + - Reads `.vscode/mcp.json` (or `%APPDATA%\Code\User\mcp.json` for user-scope). + - Renames top-level `servers` → `mcpServers`. + - Rewrites every `${input:id}` placeholder to `${ENV_VAR_NAME}` using a 5-row mapping table covering the 4 secret-bearing vault MCP servers (`github` → `GITHUB_PAT`, `tavily` → `TAVILY_API_KEY`, `context7` → `CONTEXT7_API_KEY`, `ado` → `ADO_PAT`, `brave-search` → `BRAVE_API_KEY` for future re-enablement). + - Defaults missing per-server `tools` arrays to `["*"]` (with Q-055 filed to revisit). + - Writes `$env:COPILOT_HOME\mcp-config.json` (or `~/.copilot/mcp-config.json` if `COPILOT_HOME` is unset). + - Supports `-DryRun` for previewing. +2. **CG-11 — accept the sub-agent bypass as a known limitation; mitigate by avoiding sub-agent dispatch for the 4 restricted modes.** Document the limitation in 3 places: (a) every restricted agent's body warns against being invoked via `task` ([`80 § 7.7`](80-migration-playbook.md#-77--worked-example-architect-mode--cli-agentmd) example); (b) the orchestrator agent's body forbids delegating restricted work; (c) [`80 § 8.6`](80-migration-playbook.md#-86--caveats--known-limitations) names the bug, links the issue, and pins it as a § 1 step 7 watch item. When [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) ships, the caveat is dropped wholesale and G-1 is fully closed on the CLI path. + +Both decisions are baked into the appended §§ 7–9 of [`80-migration-playbook.md`](80-migration-playbook.md). The playbook marker comment is updated to ``. + +**Rationale** + +- **Chat-as-truth (option a) wins on IDE ergonomics for this vault.** The user lives in VS Code; `.vscode/mcp.json` is what the "MCP: Open Workspace Configuration" command edits, so day-to-day MCP changes naturally land in the canonical file. Option (c) (third canonical YAML + two generators) adds an extra file no tool reads natively and is only worth it if dev-container / `.envrc` MCP configs are also being generated — they aren't, here. Option (b) (CLI-as-truth) loses the Credential-Manager-backed `${input:…}` first-run prompt UX, which is the single best secret-handling affordance on the Chat side. +- **One-way generation is simpler than round-tripping.** A round-trip generator must preserve unknowable Chat-specific fields (`inputs:` array, profile-state) on the way back from CLI; one-way avoids that. The trade-off is that any hand-edit of `mcp-config.json` is overwritten next regen — documented in [`80 § 9.4`](80-migration-playbook.md#-94--when-not-to-use-the-generator) (when NOT to use the generator). +- **CG-11 mitigation by convention is acceptable for Phase 8b-i.** The 4 restricted modes (`docs-writer`, `translate`, `docs-extractor`, `architect`) are typically used as **boot agents**, not as sub-agents in orchestrator fan-outs (per the vault's actual usage pattern noted in [Q-047](99-open-questions.md)). The risk surface is therefore narrower than the bug's worst-case description. The playbook explicitly forbids sub-agent dispatch of restricted modes in agent bodies, so the constraint is enforceable via prose discipline even though it cannot be enforced by the runtime. +- **Defers full structural enforcement to upstream.** When [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) ships, the convention can be relaxed and `task`-dispatched sub-agents will inherit the policy. No vault-side rework needed; just delete the warning paragraphs. + +**Consequences** + +- [`80-migration-playbook.md`](80-migration-playbook.md) gains §§ 7 (CLI-side config, ~9 sub-sections), 8 (preToolUse hook with full PowerShell ref impl + JSON policy table for the 4 modes + 3-place CG-11 mitigation), 9 (MCP generator + 7-row env-var mapping table). File status remains `in-progress`; marker comment updated. README Phase-8 status badge updated to reflect 8a + 8b-i complete; 8b-ii pending. +- Vault setup gets two new mandatory pieces before Stage-2: (a) the PowerShell hook script + JSON policy table at `$COPILOT_HOME/{hooks,state}/`; (b) the `generate-cli-mcp.ps1` script in `scripts/` plus 4 User-scope env vars (`GITHUB_PAT`, `TAVILY_API_KEY`, `CONTEXT7_API_KEY`, `ADO_PAT`). +- Two new open questions filed: **Q-054** (does the CLI export `$env:COPILOT_AGENT` to hook subprocesses? — would let § 8.3 drop the wrapper) and **Q-055** (per-server `tools` field round-tripping through the generator — affects security posture for high-blast-radius MCP servers). +- **Phase 8b-ii scope explicitly preserved and untouched**: no symlink/setup automation scripts, no validation matrix, no rollback plan, no Path B appendix, no executive summary. Each is named in inline `` markers throughout the new sections to make hand-off boundaries explicit. +- The Chat path remains the only surface where G-1 stays 🔴 (no hook substrate); the CLI path continues to enjoy the 🟠 demotion documented in [`50 § 13`](50-copilot-cli-research.md#13-limits--known-gaps-relative-to-roo-cli-gap-catalog--phase-5b-ii-b-2). Hybrid users get the better outcome on the surface where the work happens (CLI for restricted modes) while still using Chat for unrestricted interactive work. + +**Status** + +`accepted` + +--- + +## 2026-04-26 18:52 — Phase 8b-ii: symlink-not-copy for setup automation; 24-row table-driven validation matrix; Path B kept as a one-page appendix + +**Context** + +Phase 8b-i closed the CLI configuration cliff-edges (Q-050 + CG-11 mitigation). Phase 8b-ii had to land the four remaining sections (§§ 10–12 + Appendix B) and flip the playbook to `status: complete`. Three implementation choices were unresolved at the start of 8b-ii: (1) whether per-machine setup automation should **copy** the vault into `%USERPROFILE%\.copilot\` or **symlink** it; (2) what shape the validation matrix should take (prose runbook vs table-driven smoke tests vs scripted assertions); (3) how much depth Appendix B (Path B fallback) should carry given Path Hybrid won decisively in Phase 7. + +**Decision** + +1. **Symlink, do not copy, for both vault and user-scope consumer paths.** [`80 § 10.1`](80-migration-playbook.md#-101--scriptssetup-copilot-vaultps1-user-scope-one-time) and [`§ 10.2`](80-migration-playbook.md#-102--scriptssetup-copilot-projectps1-per-project-bootstrap) standardize on `New-Item -ItemType SymbolicLink` for everything that is "vault → consumer" (user-scope agents, instructions, hooks, state, mcp-config). Per-project `.github/` assets are **copied**, not symlinked, because they live in the project repo and must be reviewable in PRs. Symlink capability is gated by an Administrator OR Developer Mode pre-flight check (`Test-CanSymlink`) with a clear error message when neither is satisfied. +2. **Validation matrix is table-driven with copy-pasteable commands, organised in 4 buckets** (Chat / CLI / Hooks / Cross-cutting). Each row carries an ID prefixed `T-` plus a gap-ID suffix where applicable. [`80 § 11`](80-migration-playbook.md#-11--validation-matrix-phase-8b-ii) ships **24 tests** total: 8 Chat + 4 CLI core + 8 hook tests (positive + negative for each of the 4 restricted modes) + 5 cross-cutting (incl. the Q-039 latency probe and pre-commit verification). The matrix closes the `` from § 8.6 and exceeds the ≥20-test target. +3. **Appendix B is one page (5 sub-sections), not a parallel playbook.** Sub-sections cover triggers, diff vs Hybrid, section-by-section delta list, ½–1 day Hybrid → B migration estimate, and ~1 day reverse migration. References §§ 7–8 + 11.2 of the main playbook rather than re-deriving CLI content. + +Playbook frontmatter flipped `status: in-progress` → `status: complete`; marker comment updated to ``. + +**Rationale** + +- **Symlinks beat copy on every Phase-7 criterion the vault weights.** (a) Single-source-of-truth — eliminates the "did I update both?" failure mode that plagues copy-based approaches. (b) Multi-machine portability — `setup-copilot-vault.ps1` running on a second machine recreates symlinks pointing at the (presumably synced) vault, no migration. (c) Mirrors the existing `roo-vault\setup-vault.ps1` pattern the user already trusts (per [20 § Global Settings](20-roo-vault-inventory.md)). The downside (admin/Developer-Mode requirement) is a one-time cost detected by `Test-CanSymlink` rather than failing silently mid-script. The exception — per-project `.github/` assets — are copied because they're code-review artifacts that benefit from being inside the repo's diff. +- **Table-driven validation maximises hand-off readability.** A prose runbook hides the test count and makes coverage gaps invisible; scripted assertions buy precision but lock the user into a specific test framework. A table with copy-paste `cmd` + `expected` columns lets a future operator (or LLM) execute one row at a time, cite the row ID in failure reports, and re-run subsets after focused edits. The 4-bucket organization (§ 11.4) makes the "when to run what" decision mechanical: edit a `.agent.md` → run T-CHAT-01 + T-CLI-01 only; edit `mode-policies.json` → run all T-HOOK-*. +- **Appendix B's depth is bounded by Hybrid's decisive win.** Path B scored 3.70 vs Hybrid's 3.90; the gap is small enough that Path B remains a credible fallback but large enough that re-publishing 12 sections of CLI content is wasteful. The trigger conditions (B.1) are deliberately objective — "audit chat history monthly; >2 violations over 30 days" — so the switch decision is mechanical, not subjective. The reverse migration path (B.5) is documented to keep the option open if Chat catches up upstream. + +**Consequences** + +- [`80-migration-playbook.md`](80-migration-playbook.md) gains §§ 10 (3 scripts: `setup-copilot-vault.ps1`, `setup-copilot-project.ps1`, pre-commit stub), 11 (24-row validation matrix in 4 buckets + coverage summary + "when to run what"), 12 (full + 4 partial rollback scenarios + data-preservation procedure + 7-point sign-off checklist), Appendix B (5 sub-sections, ~1 page). Frontmatter status flipped to `complete`; map-of-contents (§ 0) updated to mark all 8b-ii sections ✅. +- README Phase-8 badge flipped from 🟡 in-progress to ✅ complete with the new sub-bullet enumeration. +- Three new open questions filed: **Q-056** (vault `project-templates/` subtree needs to be populated before `setup-copilot-project.ps1` is useful), **Q-057** (Q-039 latency baseline still owed; T-X-05 in the matrix is the probe), **Q-058** (symlink behaviour under OneDrive / corporate redirected profiles needs validation before enterprise rollout). +- **Phase 9 (executive summary) is the last remaining phase.** The investigation is now feature-complete — every claim made in §§ 0–10 has at least one validation row in § 11; every rollback scenario has a checklist; every fallback path is documented. Phase 9 should be a synthesis pass that distills §§ 0–12 into a 2–4 page summary for stakeholders and references the playbook for execution detail. +- **Operational ready:** a user can now (a) run `setup-copilot-vault.ps1` once, (b) run `setup-copilot-project.ps1` per repo, (c) execute the § 11 matrix to validate, (d) follow § 12 to roll back if needed, (e) switch to Appendix B if Chat proves unsuitable — without further architect-mode design work. + +**Status** + +`accepted` + +--- + +## 2026-04-26 19:00 — Phase 9 (executive summary) complete; investigation closed + +**Context** + +Phase 9 was the synthesis pass that distilled the eight prior phases into a single self-contained reader-facing document at [`00-executive-summary.md`](00-executive-summary.md). With Phase 9 shipped, every section of [`00-plan.md`](00-plan.md) has a corresponding deliverable; no open work remains in the investigation scope. This entry retrospectively closes the log. + +**Decision** + +Flip [`90-decision-log.md`](90-decision-log.md) front-matter `status: seeded` → `status: closed`. Mark the investigation feature-complete. Surface [`00-executive-summary.md`](00-executive-summary.md) as the new "START HERE" entry point in [`README.md`](README.md), demoting [`00-plan.md`](00-plan.md) to historical. No new open questions surfaced during synthesis (the memory files were internally consistent). + +Phase 9 verification: + +- [`00-executive-summary.md`](00-executive-summary.md) created with all 14 required sections (TL;DR through File Map appendix); ~370 lines; frontmatter `status: complete, phase: 9`; cites every prior phase inline. +- [`README.md`](README.md) updated: prominent "START HERE" callout above the Purpose heading; file map row inserted for `00-executive-summary.md`; Phase-9 status badge flipped 🟡 → ✅; index `status` flipped `in-progress` → `complete`. +- No edits required to [`99-open-questions.md`](99-open-questions.md) — synthesis surfaced no contradictions between memory files. + +**Rationale — what went well · what would be done differently** + +- **What went well: small subtask decomposition after early failures.** The investigation scaled past the model's single-context limit only after Phase 4 was split into 4a/b/c/d, Phase 5 into 5a/5b-i/5b-ii-A/5b-ii-B-1/5b-ii-B-2, and Phase 8 into 8a/8b-i/8b-ii. Each sub-phase was sized to fit a single subtask context with room for citations, and each closed with an explicit hand-off paragraph naming the next sub-phase's scope. This let later sub-phases reference earlier findings without re-deriving them, and kept the decision log's audit trail fine-grained enough to recover from any single bad turn. The Gap Catalog (G-/W- + CG-/CW-) standardised across Phase 4d and Phase 5b-ii-B-2 paid off enormously in Phase 6's merge. +- **What would be done differently: front-load the user-input questions.** Q-047 (vault `fileRegex` audit), Q-030 (BYOK usage), and Q-024 (Settings Sync) all required user execution, and all three landed late enough that Phase 7 / Phase 8 had to ship with conditional language ("if Q-047 returns…"). A Phase-0.5 user-questionnaire pass (5 minutes of the user's time) would have removed three layers of conditionals from the playbook and let the recommendation be more decisive on the first pass. Future similar investigations should bake a "user inputs needed before Phase N" checkpoint into [`00-plan.md`](00-plan.md) explicitly. + +**Consequences** + +- Investigation officially closed. Future memory-file edits (e.g., when [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) ships and CG-11 closes) should be filed as new dated entries in this log under a re-opened status, not as in-place edits. +- The user can begin execution against [`80-migration-playbook.md`](80-migration-playbook.md) immediately; everything they need fits in [`00-executive-summary.md`](00-executive-summary.md) §§ 9 + 12 (migration plan + next steps). +- README's index `status` is now `complete` — the next reader sees green badges across all 9 phases. + +**Status** + +`accepted` · investigation `closed` diff --git a/docs/investigation/roo-to-copilot/99-open-questions.md b/docs/investigation/roo-to-copilot/99-open-questions.md new file mode 100644 index 00000000000..82fefa886a1 --- /dev/null +++ b/docs/investigation/roo-to-copilot/99-open-questions.md @@ -0,0 +1,127 @@ +--- +phase: all +status: seeded +owner: tbd +last_updated: 2026-04-26 +sources: [] +--- + +# Open Questions + +> Parent plan: [`00-plan.md`](00-plan.md) · Index: [`README.md`](README.md) + +**Conventions:** +- Append new questions at the bottom with an ID (`Q-NNN`) and a date. +- Mark resolved questions with `~~strikethrough~~` and a link to the resolving entry in [`90-decision-log.md`](90-decision-log.md) or the findings file. Do **not** delete them. +- If a question becomes irrelevant, mark `OBSOLETE — ` rather than removing it. + +## Pre-seeded Questions (2026-04-26) + +- **Q-001 — Squad's exact role.** What is Squad at `c:/git/squad` actually for? Is it a Copilot wrapper, an orchestrator, a standalone agent, or something else? Decision needed before evaluating Path C / D in [`70-migration-paths.md`](70-migration-paths.md). Owner: Phase 3. +- ~~**Q-002 — Per-mode MCP allowlists in Copilot Chat.**~~ **RESOLVED 2026-04-26** in [`40-copilot-chat-research.md` § Custom Chat Modes (5)](40-copilot-chat-research.md#custom-chat-modes-chatmodemd) and re-confirmed in § MCP Support (4). **Yes** — `.agent.md` `tools:` frontmatter accepts individual MCP tool names or `mcpserver/*` whole-server allowlists; this **is** the only filtering mechanism (no separate `allowedMcpServers` setting outside the `tools:` allowlist). +- ~~**Q-003 — Sub-agent / orchestrator parity.**~~ **RESOLVED 2026-04-26** in [`40-copilot-chat-research.md` § Custom Chat Modes (5)](40-copilot-chat-research.md#custom-chat-modes-chatmodemd). **Partial yes** — the `agent` built-in tool plus the `agents:` frontmatter allowlist enable sub-agent dispatch; handoff buttons cover the boomerang return pattern. Roo's strict "return-to-orchestrator with summary" protocol is not 1:1; needs Phase 4d cross-check. +- ~~**Q-004 — Custom chat modes on disk (Windows).**~~ **RESOLVED 2026-04-26** in [`40-copilot-chat-research.md` § Custom Chat Modes (3)](40-copilot-chat-research.md#custom-chat-modes-chatmodemd). Workspace = `.github/agents/` (renamed from `.github/chatmodes/`); user = `%APPDATA%\Code\User\prompts\` and/or `%USERPROFILE%\.copilot\agents\`. +- **Q-005 — Auto-conversion of `.roomodes` schema.** **Partially resolved 2026-04-26** in [`40-copilot-chat-research.md` § Custom Instructions (5)](40-copilot-chat-research.md#custom-instructions-githubcopilot-instructionsmd) (mapping table). Mechanical mapping is feasible for slug/name/roleDefinition/customInstructions/allowedMcpServers; **`fileRegex`, `whenToUse`, and per-mode rules folders** have no first-class equivalent and remain lossy. Full converter spec still owned by Phase 8. + +## Added during Phase 4a (2026-04-26) + +- **Q-015 — VS Code profile-scoped user-data folders for agents/instructions/prompts.** The custom-agents doc says user-scope agents live in `~/.copilot/agents` *or* "your user data (specific to your VS Code profile)", but [`microsoft/vscode#305642`](https://github.com/microsoft/vscode/issues/305642) reports that profile-scoped user-data folders are **not** scanned today — only the global `%APPDATA%\Code\User\prompts\` folder is. **PARTIALLY RESOLVED 2026-04-26** in [`40-copilot-chat-research.md` § MCP Support (8)](40-copilot-chat-research.md#mcp-support) and § Storage Locations: `mcp.json` and `settings.json` **are** profile-scoped (`%APPDATA%\Code\User\profiles\\`); the `prompts/` folder (covering agents, prompts, instructions, tool sets) is **global**. The contradiction is doc-vs-actual on the `prompts/` folder only. Affects vault symlink design in Phase 8. Owner: Phase 4d follow-up for residual unknowns. +- **Q-016 — Release-version provenance for the `.chatmode.md` → `.agent.md` rename and AGENTS.md default-on flip.** Exact VS Code version numbers needed so the playbook can pin a minimum supported release and so the user can verify whether their current install behaves per the docs. Owner: Phase 4d. +- **Q-017 — Hard size / token limit on `copilot-instructions.md` and `.instructions.md` files.** GitHub's onboarding prompt says *"Instructions must be no longer than 2 pages"* but no enforced cap is documented in the VS Code docs. Affects whether vault-scale rule sets (multi-thousand-line composites) survive concatenation. Owner: Phase 4d / Phase 6. +- **Q-018 — Mapping Roo's `.roo/rules-/` per-mode rules folder onto Copilot.** Copilot has no per-agent rules folder; rules are either always-on (`copilot-instructions.md` / `AGENTS.md`) or `applyTo`-glob-scoped (file-pattern, not agent-pattern). Recommended pattern needed: inline into each `.agent.md` body, link from agent body via Markdown, or accept loss. Owner: Phase 8. + + + +## Added during Phase 4b (2026-04-26) + +- **Q-019 — Keybinding arguments for prompt files.** The `Chat: Run Prompt` Command Palette command opens a Quick Pick to choose a prompt; can a `keybindings.json` entry pre-select a specific prompt by name (e.g., `"command": "workbench.action.chat.runPrompt", "args": { "promptName": "review" }`)? Affects the Phase-8 playbook for users who want hotkeys mirroring Roo mode shortcuts. Owner: Phase 4d. +- **Q-020 — `${input:name}` / `${selection}` / `${file}` / `${workspaceFolder}` substitution in prompt-file bodies.** The VS Code prompt-files doc only documents free-text-after-slash arguments; community blog posts occasionally show `${input:name}` working. Is variable substitution actually supported, deprecated, or never-supported? Affects whether prompts can be parameterized with typed inputs vs. having to parse prose. Owner: Phase 4d. +- **Q-021 — Workspace-scoped `*.toolsets.jsonc`.** [`microsoft/vscode#251515`](https://github.com/microsoft/vscode/issues/251515) is open on Backlog. Until it ships, vault tool sets cannot live in the project repo; only inline `tools:` arrays in `.github/agents/*.agent.md` survive workspace-scope. Track the issue and pivot the Phase-8 playbook when it lands. Owner: Phase 4d / Phase 8. +- **Q-022 — MCP wildcard `servername/*` inside a tool set's `tools` array.** The `tools` field on `.agent.md` / `.prompt.md` accepts the `/*` wildcard; the doc for `*.toolsets.jsonc` only shows fully-qualified tool names. Is `["github/*"]` a valid entry in a tool set, or must each tool be enumerated? Owner: Phase 4d. +- **Q-023 — Tool-set nesting.** Can a tool set's `tools` array contain another tool set's name (e.g., `["#reader", "edit"]`) to compose larger sets, or are nested references silently ignored? The schema in the doc shows tool names only. Owner: Phase 4d. +- **Q-024 — Tool sets in Settings Sync.** [`microsoft/vscode#251603`](https://github.com/microsoft/vscode/issues/251603) reports that `*.toolsets.jsonc` is not synced by the "Prompts and Instructions" Settings-Sync category. Has it been added since? Affects multi-machine vault setups. Owner: Phase 4d. + +## Added during Phase 4c (2026-04-26) + +- **Q-025 — Residual MCP unknowns.** Several smaller MCP details could not be resolved from public docs as of 2026-04-26: (a) is the GitHub-doc `requestInit.headers` form fully equivalent to VS Code's `headers` field on HTTP servers? (b) what is the exact secret-storage namespace key on Windows (which Credential Manager entry holds the `${input:…}` resolved values)? (c) is the MCP server enable/disable state itself synced via Settings Sync, or only the `mcp.json` content? (d) which MCP-source clients does `chat.mcp.discovery.enabled` actually scan today (Claude Desktop confirmed; Cursor / Continue / Windsurf inferred from community posts only)? Owner: Phase 4d / Phase 8. +- **Q-026 — Vault `mcp.json` symlink automation across multiple VS Code profiles.** Default-profile symlink at `%APPDATA%\Code\User\mcp.json` is straightforward; named profiles need `%APPDATA%\Code\User\profiles\\mcp.json` linked individually, and `` is a generated short ID (not the human profile name). Need a Phase-8 PowerShell helper that enumerates `%APPDATA%\Code\User\profiles\*\` and re-points each profile's `mcp.json` to the vault. Owner: Phase 8. + +## Added during Phase 1–3 inventory (2026-04-26) + +- **Q-006 — Layered-rules precedence: `AGENTS.md` vs `.roo/rules/`.** When both are present at the same scope, which wins, and is the order the same for global (`~/.roo/`) vs project (`./.roo/`)? See [`src/core/prompts/sections/custom-instructions.ts`](../../../src/core/prompts/sections/custom-instructions.ts) (`loadRuleFiles`, `loadAllAgentRulesFiles`, `addCustomInstructions`). Affects how a Copilot/Squad replacement must merge instructions. Owner: Phase 1 follow-up / Phase 6. +- **Q-007 — Subfolder-rules feature flag default.** `loadRuleFiles(cwd, enableSubfolderRules)` and `getAllRooDirectoriesForCwd` traverse subdirectories only when subfolder rules are enabled. What is the production default for the user, and does the vault rely on it? Owner: Phase 1 follow-up. +- ~~**Q-008 — Vault symlink portability.**~~ **RESOLVED 2026-04-26** in [`50-copilot-cli-research.md` § 2.1](50-copilot-cli-research.md#21-path-layout) and § 6.4. Copilot CLI exposes a first-class `COPILOT_HOME` env var **and** a per-invocation `--config-dir` flag that redirect every config sub-path (settings, agents, skills, instructions, hooks, MCP, sessions). Symlinks work as a fallback; `COPILOT_HOME` is cleaner. Combined with the Phase-4c finding (Copilot Chat reads symlinked `%APPDATA%\Code\User\prompts\` and profile-scoped `mcp.json`), portability is confirmed for both target paths. Vault bootstrap simplifies to `[Environment]::SetEnvironmentVariable("COPILOT_HOME", "/global-settings/copilot", "User")`. +- ~~**Q-009 — Per-mode `allowedMcpServers` semantics: empty array vs unset.**~~ **RESOLVED 2026-04-26** in [`40-copilot-chat-research.md` § MCP Support (8)](40-copilot-chat-research.md#mcp-support). **Empty array means "no MCP servers"** — the filter at [`src/core/prompts/tools/native-tools/mcp_server.ts:22`](../../../src/core/prompts/tools/native-tools/mcp_server.ts:22) treats `[]` as truthy and intersects to nothing. Vault's `code` mode therefore explicitly disables MCP. Copilot equivalent: omit all `/…` entries from `.agent.md` `tools:`. +- ~~**Q-010 — Squad ↔ `vscode.lm` vs `@github/copilot-sdk`.**~~ **RESOLVED 2026-04-26** in [`50-copilot-cli-research.md` § 6.2](50-copilot-cli-research.md#62-squad--vscodelm-resolves-q-010). Squad depends **only** on `@github/copilot-sdk`; it has no `vscode.lm`, `vscode`, or `@vscode/*` dependency. Squad is **strictly external CLI-driven** and cannot be embedded inside a VS Code extension as-is. Path-D (vault-as-VSIX) cannot reuse squad without re-implementing its orchestration on top of `vscode.lm`. +- **Q-011 — Squad alpha stability for daily-driver use.** Squad is published as v0.9.1 alpha ([`../squad/package.json`](../../../../squad/package.json)). What is the project's stability commitment, breaking-change cadence, and Windows support state? Affects Path C/D viability. Owner: Phase 7. +- **Q-012 — Roo's secret-handling policy in MCP settings vs vault commit policy.** Vault's `global-settings/mcp_settings.json` contains live API tokens (intentionally tracked per repo notes). Does the migration target (Copilot MCP config or Squad's `.copilot/mcp-config.json`) require secrets in env vars instead of inline JSON, and how does that interact with the vault's symlink-and-commit pattern? Owner: Phase 2 follow-up / Phase 8. +- ~~**Q-013 — Sequential-only enforcement test parity.**~~ **RESOLVED 2026-04-26** in [`40-copilot-chat-research.md` § Agent Mode (8.4)](40-copilot-chat-research.md#agent-mode). VS Code subagents (`runSubagent` tool) are **parallel-capable by default** — the model may dispatch multiple subagents in one turn, with recursion enabled by `chat.subagents.allowInvocationsFromSubagents` (max depth 5). Roo's strict-sequential semantics are achievable in Copilot only by **prose discipline in the parent agent's body** ("dispatch one subagent at a time and wait for it to return before starting the next"); they are **not enforced by the runtime**. Net assessment: 🟡 minor gap (G-4 in the Gap Catalog) — sequential parity is best-effort prompt-shaped, but parallel dispatch enables several Copilot-only wins (parallel review, multi-model consensus). Workflows that genuinely depend on strict sequencing must be expressed as a single non-decomposed agent or split across separate user turns. +- **Q-014 — Webview UI parity.** **PARTIALLY RESOLVED 2026-04-26** in [`40-copilot-chat-research.md` § Chat Participants / Extension API (5–6)](40-copilot-chat-research.md#chat-participants--extension-api). Copilot Chat ships a single unified panel (one panel for all participants/agents/modes) vs Roo's webview with `ModesView.tsx` / `McpServerRestriction.tsx` / `DeleteModeDialog.tsx`. Mode CRUD in Copilot is **file-backed** (edit `.agent.md` directly or use Command Palette `Chat: New Agent…` / `Chat: Configure Tool Sets…`); per-MCP-server allowlists are encoded inline in `tools:` rather than via a UI. Remaining unknown: which of the Roo webview affordances the user actually depends on day-to-day. Owner: user input needed before Phase 6. + +## Added during Phase 4d (2026-04-26) + +- **Q-027 — Extension manifest path for shipping `.agent.md` outside the Agent Plugins (Preview) channel.** Agent Plugins is the supported declarative channel for an extension to publish agents, but it is marked Preview and is gated behind `chat.agentPlugins.enabled`. Is there a stable `contributes.chatAgents` (or similar) entry point in `package.json` that ships `.agent.md` from a VSIX without joining the Plugins channel, or is the Language Model Tools API + `vscode.chat.createChatParticipant` the only stable surface? Affects whether vault-as-VSIX (Path D in Phase 7) can be GA-ready or remains Preview-bound. Owner: Phase 7. +- **Q-028 — Org-management story for Agent Plugins.** Once `chat.agentPlugins.enabled` is on, what controls do orgs have over which plugins users may install (allowlist, signature requirements, GitHub Marketplace gating)? The `github.copilot.chat.policies.*` settings cover built-in features but plugin-publishing policy is not documented. Affects Phase-8 governance for multi-developer rollouts. Owner: Phase 4 follow-up / Phase 8. +- **Q-029 — Chat sessions JSON export / import portability.** Multi-session chat lists sessions and supports fork/checkpoint, but there is no documented `chat.sessions.export` command or stable on-disk JSON schema (sessions live in profile-scoped state DB). Can a user back up / move / diff chat sessions across machines, or is the only retention story "leave the panel open"? G-9 in the Gap Catalog hinges on this. Owner: Phase 4 follow-up / Phase 8. +- **Q-030 — Does the vault rely on a non-Copilot model provider today?** Roo accepts arbitrary OpenAI-compatible endpoints (Ollama, LM Studio, OpenRouter, Anthropic direct, Azure OpenAI). VS Code Copilot Chat in agent/sub-agent mode currently restricts model picker to GitHub-curated providers (G-13 🟠). If the vault uses a local model (e.g., Ollama for offline / cost-control workflows), Phase-7 must include a Plan-B (e.g., Continue.dev side-by-side, or Squad as a model-bridging layer). **PARTIALLY RESOLVED for the CLI path 2026-04-26** in [`50-copilot-cli-research.md` § 7](50-copilot-cli-research.md#7-sdk-githubcopilot-sdk-surface--headline-only) — the CLI honours `COPILOT_PROVIDER_BASE_URL` / `COPILOT_PROVIDER_TYPE` (openai/azure/anthropic) / `COPILOT_PROVIDER_API_KEY` / `COPILOT_MODEL` BYOK env vars; Ollama via OpenAI-compat endpoint works. The Chat-side restriction stands. User input still needed to confirm vault's actual model usage. Owner: Phase 6 / Phase 7. + +## Added during Phase 5a (2026-04-26) + +- **Q-031 — Squad's non-standard MCP config location.** Squad uses `.copilot/mcp-config.json` at the project root — a **user-format file in a project-scope directory** — relying on the squad launcher implicitly setting `COPILOT_HOME=.copilot/`. The CLI's documented project-scope MCP location is `.github/mcp.json` (not `.copilot/mcp-config.json`). Is the squad pattern a deliberate convention worth adopting in the vault, or an accidental coupling that breaks if a user runs `copilot` directly (without the squad launcher) from a squad-style project? Affects Phase-8 playbook for any project that wants to layer squad on top. Owner: Phase 5b / Phase 8. +- **Q-032 — Repository `settings.json` allowlist scope.** The CLI accepts only six keys at the repo layer (`companyAnnouncements`, `disableAllHooks`, `enabledPlugins`, `extraKnownMarketplaces`, `hooks`, `mergeStrategy`). The vault wants to ship per-project `allowedTools`/`deniedTools`/`systemPrompt` overrides; those are silently ignored at the repo layer. Workarounds: (a) ship them in `.github/copilot/settings.local.json` (not committed; defeats vault portability), (b) push them down into per-agent `.agent.md` `tools:` arrays, (c) wrap `copilot` in a project-local launcher that exports the desired flags. Pick one for the playbook. Owner: Phase 8. +- **Q-033 — `${VAR}` env-substitution semantics across MCP config layers.** Both the CLI's `mcp-config.json` and squad's `.copilot/mcp-config.json` use `${VAR}` substitution from the **process env**, not from a `.env` file. VS Code Copilot Chat uses `${input:id}` with Credential-Manager-backed first-run prompts. There is therefore no shared secret-handling story between Chat and CLI: the same MCP server requires a different config in each. Recommend a single canonical pattern for the vault (e.g., `.copilot/.env` loaded by a wrapper that exports vars before invoking `copilot`). Owner: Phase 8. +- **Q-034 — Sub-agent depth & concurrency caps interact with `task` orchestrator patterns.** Default sub-agent depth = 6, concurrency = 32. Roo's orchestrator pattern in the vault is single-level + sequential. Squad routinely runs depth-2 fan-outs at concurrency ~10. Whether the vault's planned migration patterns ever hit those caps is unknown; if the user wants nested orchestrators (orchestrator delegates to a sub-orchestrator that delegates to workers), depth-3+ must be tested. Owner: Phase 7. +- ~~**Q-035 — `preToolUse` hook as `fileRegex` substitute on Windows.**~~ **PARTIALLY RESOLVED 2026-04-26** in [`50-copilot-cli-research.md` § 10.4](50-copilot-cli-research.md#104-pretooluse-deep-dive--the-fileregex-substitute) and § 10.6 verdict. **Yes-with-caveats:** payload exposes `toolName` + `toolArgs.path` (after JSON parse); `{permissionDecision:"deny",permissionDecisionReason}` JSON output blocks the call; a working PowerShell reference implementation is in § 10.4. **Caveats:** (a) sub-agent bypass bug [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392) means `task`-dispatched sub-agents currently leak; (b) parallel-call race [`copilot-cli#2893`](https://github.com/github/copilot-cli/issues/2893); (c) plugin-hook bug [`copilot-cli#2540`](https://github.com/github/copilot-cli/issues/2540); (d) `modifiedArgs` not honoured [`copilot-cli#2013`](https://github.com/github/copilot-cli/issues/2013); (e) active agent name not in payload (Q-037). Net: G-1 becomes 🟠 major on the CLI path (vs 🔴 blocker on Chat). Latency / env inheritance follow-ups split into Q-039/Q-040. + +## Added during Phase 5b-i (2026-04-26) + +- ~~**Q-031 — Squad's non-standard MCP config location.**~~ **RESOLVED 2026-04-26** in [`50-copilot-cli-research.md` § 9.1](50-copilot-cli-research.md#91-canonical-config-locations--precedence--resolves-q-031). The CLI's documented project-scope MCP location is `.github/mcp.json` (or `.mcp.json` at repo root). Squad's `.copilot/mcp-config.json` is **not** a CLI discovery default; it works only because squad's launcher implicitly sets `COPILOT_HOME` to the project's `.copilot/` directory. Recommendation for the vault: prefer `.github/mcp.json` for project-scope MCP and `~/.copilot/mcp-config.json` (via `COPILOT_HOME`) for the user/vault layer. +- ~~**Q-033 — `${VAR}` env-substitution semantics across MCP config layers.**~~ **RESOLVED 2026-04-26** in [`50-copilot-cli-research.md` § 9.3](50-copilot-cli-research.md#93-auth--secrets-on-windows--resolves-q-033). The CLI uses **process-env substitution only** (`$VAR` / `${VAR}` / `${VAR:-default}`); there is no `${input:…}` Credential-Manager prompt as on the Chat side, and the OS keychain is reserved for the GitHub auth token. **No shared secret-handling story exists between Chat and CLI** — vault must pick one canonical source (recommend user-scope env vars set via `[Environment]::SetEnvironmentVariable(…, "User")`) and generate the other format mechanically. +- **Q-032 (refined).** Repo-layer settings still ignore `allowedTools` / `deniedTools` / `systemPrompt`, but `disableAllHooks` and `hooks` **are** honoured at the repo layer (six-key allowlist) — confirmed in [`50-copilot-cli-research.md` § 10.5](50-copilot-cli-research.md#105-disableallhooks-kill-switch--resolves-q-032). Vault can therefore ship per-project hook policy via committed `.github/copilot/settings.json` or `.github/hooks/*.json`, but per-project tool allowlists still need a launcher wrapper or per-agent inlining. Q-032 stays open for the tool-allowlist scope; the hook scope is resolved. +- **Q-036 — User-scope hook discovery path.** Phase-5b-i § 10.1 lists `~/.copilot/config.json`'s inline `hooks` key as the documented user-scope hook location; whether the CLI also scans `~/.copilot/hooks/*.json` (parallel to `.github/hooks/*.json`) is referenced in some community sources but not in the canonical [cli-command-reference § Hooks](https://docs.github.com/en/enterprise-cloud@latest/copilot/reference/copilot-cli-reference/cli-command-reference#hooks-reference). Confirm before the Phase-8 playbook recommends a vault-symlink target. Owner: Phase 8. +- **Q-037 — Active-agent identity in `preToolUse` payload.** The hook payload exposes `toolName`, `toolArgs`, `cwd`, `sessionId`, `timestamp`. It does **not** expose the active `--agent` name or sub-agent depth. The recommended workaround in [`50-copilot-cli-research.md` § 10.4](50-copilot-cli-research.md#104-pretooluse-deep-dive--the-fileregex-substitute) is a sidecar state file written from `subagentStart`, but that adds moving parts. Either (a) confirm an undocumented env var exposes the agent name to spawned hooks, or (b) file a feature request for `agentName` in the payload. Owner: Phase 8 / upstream. +- **Q-038 — CLI hook types: `command` + `prompt` only?** [Hooks-configuration reference](https://docs.github.com/en/copilot/reference/hooks-configuration) and the CLI command reference document only `command` and `prompt`; the Phase-5a stub claimed an `http` type with HTTPS-required model. The `http` model exists for the **Cloud agent** hooks ([cloud-agent/about-hooks](https://docs.github.com/en/copilot/concepts/agents/cloud-agent/about-hooks)) but appears not to apply to the CLI. Confirm against the SDK's `Hook` interface in `@github/copilot-sdk` before the playbook claims any HTTP-hook capability for the CLI. Owner: Phase 5b-ii (SDK surface). +- **Q-039 — `pwsh -NoProfile -Command` cold-start latency on the user's box.** § 10.4 estimates 150–400 ms typical, >1 s with module loads. Empirical measurement on the user's Windows 11 dev box needed to size the per-tool overhead before recommending hook-heavy policies in the Phase-8 playbook. Suggested probe: `Measure-Command { 1..20 | % { pwsh -NoProfile -Command 'exit 0' } }`. Owner: Phase 8. +- **Q-040 — `${env:VAR}` expansion inside hook entry `env` map.** MCP config supports `$VAR` / `${VAR}` / `${VAR:-default}` expansion in its `env` map. Hooks documentation describes the entry's `env` map as "Environment variables to set (supports variable expansion)" but does not specify the expansion syntax or whether it matches MCP. Owner: Phase 5b-ii. + +## Added during Phase 5b-ii-A (2026-04-26) + +- **Q-041 — `user-invocable` / `disable-model-invocation` SKILL.md frontmatter on the Copilot CLI.** The cross-tool [Agent Skills standard](https://agentskills.io/) (and Claude Code's CLI) accepts `user-invocable: true|false` and `disable-model-invocation: true|false` for slash-menu visibility and autonomous-use control. Copilot's [add-skills doc](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/add-skills) documents only `name`, `description`, `license`, `allowed-tools`. Confirm whether the CLI silently ignores those fields or whether they have an undocumented effect. Reference: cross-tool consistency thread [`anthropics/claude-code#18737`](https://github.com/anthropics/claude-code/issues/18737) (allowed-tools subset behaviour) and the Copilot CLI's own [`vscode-copilot-release#14131`](https://github.com/microsoft/vscode-copilot-release/issues/14131) (validator gap). Owner: Phase 5b-ii-B. +- **Q-042 — Structured event-stream output for the CLI (`--output-format json` / `stream-json`).** Verified absent from current docs; tracked upstream as [`copilot-cli#52`](https://github.com/github/copilot-cli/issues/52). The Phase-5a § 3.4 stub overstated this; § 12.1 of [`50-copilot-cli-research.md`](50-copilot-cli-research.md#121-correction-to-phase-5a-stub-structured-json-output-is-not-shipped) is now the corrected source of truth. **Until shipped**, automation that needs structured events must drop down to `@github/copilot-sdk` (streaming-events channel). Adds 🟠 G-6 to the CLI Gap Catalog (formalised in Phase 6). Owner: track upstream + Phase 6. +- **Q-043 — Granular non-zero exit codes.** Documented as "non-zero on failure" without distinguishing auth-fail vs permission-deny vs context-cap vs network. CI consumers that need to retry transient failures but fail-fast on auth must currently parse stderr. Confirm whether the CLI exposes a stable exit-code table anywhere (or via `copilot --help` undocumented in the web ref). Owner: Phase 8. + +## Added during Phase 5b-ii-B-2 (2026-04-26) + +- **Q-047 — Vault's actual `fileRegex` usage breadth.** The CLI Gap Catalog ([`50-copilot-cli-research.md` § 13](50-copilot-cli-research.md#13-limits--known-gaps-relative-to-roo-cli-gap-catalog--phase-5b-ii-b-2)) demotes G-1 from 🔴 (Chat) to 🟠 (CLI) on the strength of the `preToolUse` hook, but the demotion's binding constraint is CG-11 (`task`-dispatched sub-agents bypass `preToolUse`, [`copilot-cli#2392`](https://github.com/github/copilot-cli/issues/2392)). To finalise the severity in Phase 6, count how many vault modes actually use `fileRegex` *and* are dispatched as sub-agents from the orchestrator (vs. used only as the boot agent via `--agent`). If the answer is "few or none of the restricted modes are sub-agent-dispatched", G-1 stays 🟠; if many are, G-1 effectively re-escalates to 🔴 on the CLI until the upstream bug ships. Owner: Phase 6. + +## Added during Phase 5b-ii-B-1 (2026-04-26) + +- **Q-044 — `acpServer` export presence in current SDK.** Phase-5a § 7 stub listed `acpServer` (Agent Client Protocol mount) as an export. The current [`nodejs/README.md`](https://github.com/github/copilot-sdk/blob/main/nodejs/README.md) API reference at v0.3.0 does not surface this name in its top-level table of contents; it may have been (a) renamed, (b) moved to a sub-path export, (c) deprecated, or (d) retained but not headline-documented. Confirm by reading the published `dist/index.d.ts` of `@github/copilot-sdk@0.3.0` (e.g., `npm view @github/copilot-sdk dist-tags` then `npm pack` and inspect). Affects Path-D's ability to expose the SDK session as an ACP server to other editors. Owner: Phase 7. +- **Q-045 — Programmatic MCP-server registration helper in the SDK.** The readme documents file-based MCP discovery (CLI's `mcp-config.json`) and shows `kind: "mcp"` in the permission-handler enum, but does **not** show a programmatic `addMcpServer(...)` / `mcpServers:` field on `createSession(config)`. Squad's adapter layer also does not exercise such a helper. Determine whether MCP servers can be registered purely from code (no on-disk config), which matters for VSIX embedding (no writeable `~/.copilot/` in some sandboxed contexts). Owner: Phase 7 / 8. +- **Q-046 — Bundling the CLI binary inside a VSIX.** Path-D requires either (a) declaring `@github/copilot` as a peer dep that the user installs separately, or (b) bundling the CLI inside the VSIX. Option (b) raises VSIX size (CLI is tens of MB), Marketplace size limits, code-signing on Windows, and auto-update (CLI ships its own self-updater that may conflict with VS Code's extension-update lifecycle). Option (a) is operationally simpler but degrades first-run UX. Decide before scoring Path D in Phase 7. Owner: Phase 7. + +## Added during Phase 6 (2026-04-26) + +- **Q-048 — `AGENTS.local.md` (or equivalent) gitignored-personal-overrides convention.** Roo's layered rules system lets a user drop personal `*.local.md` files alongside committed rules and have both concatenated. Copilot's `AGENTS.md` cascade (Personal > Repository > Organization, all-files-concatenated within a tier) does not document a `.local` suffix or any `.gitignore`-aware variant; the only "personal" tier is the user-scope `~/.copilot/` / `%APPDATA%\Code\User\prompts\` location, which is not co-located with the repo. Confirm whether VS Code Copilot Chat or the Copilot CLI honour `AGENTS.local.md` (or any documented suffix) for committed-repo + gitignored-overlay composition; if not, the vault must move personal overrides to user-scope or invent a build-time concatenation step. Affects vault portability for per-project personal tweaks. Owner: Phase 8. +- **Q-049 — Roo's todo-list re-injection (`update_todo_list` tool) has no Copilot equivalent.** Roo automatically re-injects the current todo list into the system prompt of every turn so the agent always sees outstanding work. Copilot Chat's working-set + checkpoints and the CLI's session-resume model both persist *conversation* state but neither has a documented mechanism for "always include this list verbatim at top of system prompt every turn until the user clears it". Without an equivalent, long-running orchestrator-style tasks rely on the agent re-reading a markdown file each turn (extra tool call, no guarantee). Confirm whether a hook (`userPromptSubmitted` injecting context into the prompt stream) or the SDK's session API can synthesise this behaviour, and whether `disableAllHooks` or repo policy can disable it inappropriately. Surfaced during Phase 6 § F.4. Owner: Phase 7 / Phase 8. + +## Added during Phase 7 (2026-04-26) + +- **Q-050 — Canonical-source decision for the dual-format MCP config under Path Hybrid.** Hybrid ships two MCP files per project: `.vscode/mcp.json` (`servers:` shape + `inputs:` array) for Chat and `.github/mcp.json` (`mcpServers:` shape + env-var substitution) for CLI. Phase 6 § F.2 / [`50-copilot-cli-research.md` § 9.1](50-copilot-cli-research.md#91-canonical-config-locations--precedence--resolves-q-031) recommend a one-shot `jq '{mcpServers: .servers}'` migration but do not specify which file is the **truth** going forward. Three candidate designs: (a) author a third file `mcp.canonical.yaml` with two generators; (b) treat `.vscode/mcp.json` as truth and generate the CLI shape on commit; (c) treat `.github/mcp.json` as truth and generate the Chat shape. Each has trade-offs (extra file vs IDE-native ergonomics vs CLI-native ergonomics). Phase 8 must pick one and ship the converter. Owner: Phase 8. +- **Q-051 — `AGENTS.md` ↔ `AGENTS.local.md` dual-surface read order.** Q-048 asks *whether* `AGENTS.local.md` is read by either surface; Q-051 asks how it composes when **both** Chat (`chat.useAgentsMdFile`) and CLI (native AGENTS.md ingestion) read the same project on the same machine. Specifically: do both surfaces concatenate `AGENTS.md` + `AGENTS.local.md` in the same order? Does either surface respect `.gitignore` semantics for the `.local` suffix automatically? Affects whether the user can keep personal-overlay rules in one file readable from both surfaces. Owner: Phase 8. **Verification recipe shipped 2026-04-26** in [`80-migration-playbook.md` § 2.1](80-migration-playbook.md#-21--agentsmd-project-root) (token-quote test). + +## Added during Phase 8a (2026-04-26) + +- **Q-052 — Precise group→tools expansion table for Roo's `command`, `browser`, and composite groups.** [`80-migration-playbook.md` § 2.2](80-migration-playbook.md#-22--agentmd-schema-and-conversion) provides the canonical Roo-`groups` → Copilot-`tools:` mapping for `read`, `edit`, and `mcp`, but the expansions for `command` (mapped tentatively to `runInTerminal`), `browser` (mapped tentatively to `openSimpleBrowser`), and any composite/conditional group entries are best-effort. Confirm against [`src/core/prompts/tools/native-tools/`](../../../src/core/prompts/tools/native-tools) which exact native-tool names back each Roo group, and whether Copilot has a closer 1:1 (e.g., for browser tools, `vscode-browser` extension tools vs `openSimpleBrowser`). Affects the `tools:` column in [`80 § 4`](80-migration-playbook.md#-4--17-mode-mapping-table) for ≥10 of 17 modes. Owner: Phase 8b. +- **Q-053 — `.agent.md` `agents:` allowlist value form: emoji display name vs kebab-case slug.** The vault uses display names like `🏗️ Architect` (with emoji) for `name:`. The Phase-4a custom-agents schema example shows `agents: ['Planner', 'Implementer']` (display-name form). It is unclear whether: (a) the value must match `name:` verbatim including emoji, (b) the value matches the filename stem (`architect`), or (c) both forms are accepted with case-insensitive matching. Affects every `agents:` entry in the worked architect example ([`80 § 2.2`](80-migration-playbook.md#-22--agentmd-schema-and-conversion)) and the orchestrator agent's subagent allowlist ([`80 § 4` row 17](80-migration-playbook.md#-4--17-mode-mapping-table)). Test by authoring two minimal agents (`Foo` with emoji name, `bar.agent.md` filename) and trying both forms in a third agent's `agents:` array. Owner: Phase 8b. + +## Added during Phase 8b-i (2026-04-26) + +- **Q-054 — Does Copilot CLI export an env var carrying the active agent name to spawned hook processes?** The `preToolUse` payload does not include the agent name (Q-037 / CG-13). The Phase 8b-i reference impl in [`80-migration-playbook.md` § 8.3](80-migration-playbook.md#-83--active-agent-discovery-cg-13-mitigation) uses a sidecar file at `$COPILOT_HOME/state/active-agent.txt` written by a wrapper script (Option A) because env-var Option B is unverified. Confirm whether `$env:COPILOT_AGENT` (or `COPILOT_ACTIVE_AGENT`, `COPILOT_SUBAGENT_NAME`, etc.) is set in the hook subprocess environment. Quick probe: temporarily replace `enforce-file-regex.ps1` with `Get-ChildItem env: | Where-Object Name -like '*COPILOT*' | Out-File "$env:COPILOT_HOME\state\hook-env-dump.txt"` and run a session under `--agent architect`. If found, switch the hook to Option B and drop the wrapper. Owner: Phase 8b-ii / upstream. Filed during Phase 8b-i. +- **Q-055 — Per-server `tools` field on `.vscode/mcp.json` for round-tripping through `generate-cli-mcp.ps1`.** The Chat schema does not have a `tools:` field on individual server entries (filtering is done in `.agent.md` `tools:`). The CLI schema requires `tools` per server. The Phase 8b-i generator ([`80 § 9.1`](80-migration-playbook.md#-91--generator-script--scriptsgenerate-cli-mcppspowershell)) defaults missing `tools` to `["*"]`. Investigate: (a) is there a way to express per-server tool allowlists in Chat (e.g., a sidecar comment or non-standard field VS Code preserves)? (b) should the canonical `.vscode/mcp.json` carry a non-standard `_cli_tools` extension key for the generator to lift? Affects vault security posture for high-blast-radius MCP servers (e.g., `github` with write scope). Owner: Phase 8b-ii. + +## Added during Phase 8b-ii (2026-04-26) + +- **Q-056 — Vault `project-templates/` subtree convention.** [`80-migration-playbook.md` § 10.2](80-migration-playbook.md#-102--scriptssetup-copilot-projectps1-per-project-bootstrap) assumes a `roo-vault\copilot-home\project-templates\` directory exists holding the per-project bootstrap assets (`.github/agents/`, `.github/instructions/`, `.vscode/mcp.json`, `AGENTS.md`, `hooks/pre-commit`). The vault does not yet ship this folder; the user must populate it once before `setup-copilot-project.ps1` is useful. Decide: (a) ship a starter pack as part of `setup-copilot-vault.ps1` (creates a minimal `project-templates/` with example files); (b) document the expected layout and let the user assemble it manually; (c) pull templates directly from a GitHub repo on first run. Owner: Phase 9 or first-project rollout. +- **Q-057 — Hook latency baseline on the user's box (Q-039 follow-up; T-X-05 in § 11.3).** The validation matrix specifies a < 400 ms mean target for `enforce-file-regex.ps1` per call (T-X-05) but the actual measurement on the user's Windows 11 dev box has not been taken. Run the probe once during Stage-1 → Stage-2 cutover and record the result here. If > 1 s, escalate to a compiled hook (e.g., a tiny Go binary) or accept a per-tool-call slowdown documented in the playbook. Owner: Stage-2 cutover. +- **Q-058 — Symlink behaviour across OneDrive / cloud-synced user profiles.** [`80 § 10.1`](80-migration-playbook.md#-101--scriptssetup-copilot-vaultps1-user-scope-one-time) creates symlinks under `%USERPROFILE%\.copilot\` and `%APPDATA%\Code\User\prompts\`. If the user's profile lives in OneDrive (`Settings → Accounts → Backup`) or a corporate redirected-folder setup, NTFS symlink semantics may degrade (OneDrive historically blocked junctions; some redirected profiles strip reparse points). Validate before recommending the script to enterprise users. Owner: first cross-machine deployment. diff --git a/docs/investigation/roo-to-copilot/README.md b/docs/investigation/roo-to-copilot/README.md new file mode 100644 index 00000000000..721a8b5a667 --- /dev/null +++ b/docs/investigation/roo-to-copilot/README.md @@ -0,0 +1,83 @@ +--- +phase: index +status: complete +owner: architect-subtask +last_updated: 2026-04-26 +sources: + - docs/investigation/roo-to-copilot/10-roo-inventory.md + - docs/investigation/roo-to-copilot/20-roo-vault-inventory.md + - docs/investigation/roo-to-copilot/30-squad-inventory.md +--- + +# Roo-Code → GitHub Copilot Migration Investigation + +> 📌 **START HERE → [`00-executive-summary.md`](00-executive-summary.md)** — single self-contained 5–10 minute read covering the recommendation (**Path Hybrid: Copilot Chat + CLI**), the gap landscape, and a 10-step rollout plan. All other files in this folder are supporting detail. + +## Purpose + +This memory-file set tracks a long-running investigation into the question: + +> **How do I leave Roo-Code and recreate the same experience using GitHub Copilot (Chat extension and/or CLI), with Squad as a possible intermediary?** + +The user's verbatim goal: replicate the Roo-Code experience — **modes, orchestrator, MCP, custom prompts, rules, memory** — in **GitHub Copilot Chat** and/or **Copilot CLI**, possibly via **Squad**; ultimately leave Roo-Code. + +## Decision Question + +> **Squad vs Copilot Chat built-ins vs Copilot CLI built-ins — which path?** + +Sub-questions: + +- Can Copilot Chat's custom chat modes + prompt files + MCP fully replace Roo modes/orchestrator/MCP? +- Does Copilot CLI offer enough automation surface to replace Roo for terminal workflows? +- Does Squad add value as a translation/orchestration layer, or is it redundant? +- What is the minimal-effort migration path that preserves the [`roo-vault`](../../../../roo-vault) multi-project layout? + +## File Map + +| File | Phase | Description | +|------|-------|-------------| +| [`README.md`](README.md) | — | This index. Read first. | +| [`00-executive-summary.md`](00-executive-summary.md) | 9 | **START HERE.** Self-contained 5–10 minute summary; recommendation = Path Hybrid; 10-step rollout. | +| [`00-plan.md`](00-plan.md) | All | Investigation plan, goals, methodology, 9-phase breakdown (historical; superseded as entry point by `00-executive-summary.md`). | +| [`10-roo-inventory.md`](10-roo-inventory.md) | 1 | Inventory of Roo-Code features to replicate. | +| [`20-roo-vault-inventory.md`](20-roo-vault-inventory.md) | 2 | Inventory of the user's `roo-vault` multi-project layout. | +| [`30-squad-inventory.md`](30-squad-inventory.md) | 3 | Investigation of Squad at `c:/git/squad`. | +| [`40-copilot-chat-research.md`](40-copilot-chat-research.md) | 4 | Research on GitHub Copilot Chat (VS Code). | +| [`50-copilot-cli-research.md`](50-copilot-cli-research.md) | 5 | Research on GitHub Copilot CLI. | +| [`60-gap-analysis.md`](60-gap-analysis.md) | 6 | Roo-vs-Copilot/Squad feature gap matrix. | +| [`70-migration-paths.md`](70-migration-paths.md) | 7 | Candidate migration paths A/B/C/D with trade-offs. | +| [`80-migration-playbook.md`](80-migration-playbook.md) | 8 | Concrete file-by-file migration playbook. | +| [`90-decision-log.md`](90-decision-log.md) | All | Append-only decision log. Read first. | +| [`99-open-questions.md`](99-open-questions.md) | All | Running list of unresolved questions. | + +## How to Use These Memory Files + +Future agents working on this investigation **must**: + +1. **Always read first**, in this order: + - [`README.md`](README.md) (this file) + - [`00-plan.md`](00-plan.md) (the plan and methodology) + - [`90-decision-log.md`](90-decision-log.md) (what has already been decided) +2. **Append, do not overwrite.** Findings files grow over time. Preserve prior content; add new sections with dated headings. +3. **Date every entry.** Use ISO-8601 (`YYYY-MM-DD`) at minimum; `YYYY-MM-DD HH:MM` for the decision log. +4. **Cite sources.** Every factual claim about Copilot, Squad, or Roo internals must include a URL and access date in the file's `sources:` front-matter and inline near the claim. +5. **Update the front-matter** `status` and `last_updated` fields on every edit. +6. **Log decisions** in [`90-decision-log.md`](90-decision-log.md) — never silently change direction. +7. **Open questions** go in [`99-open-questions.md`](99-open-questions.md) as soon as they arise; remove or strike through only when resolved (with a link to the resolving decision). + +## Status Badges + +| Phase | File | Status | Last updated | +|-------|------|--------|--------------| +| 0 — Scaffolding | [`README.md`](README.md), [`00-plan.md`](00-plan.md) | ✅ scaffold complete | 2026-04-26 | +| 1 — Roo inventory | [`10-roo-inventory.md`](10-roo-inventory.md) | ✅ complete | 2026-04-26 | +| 2 — roo-vault inventory | [`20-roo-vault-inventory.md`](20-roo-vault-inventory.md) | ✅ complete | 2026-04-26 | +| 3 — Squad inventory | [`30-squad-inventory.md`](30-squad-inventory.md) | ✅ complete | 2026-04-26 | +| 4 — Copilot Chat research | [`40-copilot-chat-research.md`](40-copilot-chat-research.md) | ✅ complete (4a + 4b + 4c + 4d — agents/instructions, prompt files, tool sets, MCP, Windows storage, agent mode + sub-agents, chat extension API, Gap Catalog) | 2026-04-26 | +| 5 — Copilot CLI research | [`50-copilot-cli-research.md`](50-copilot-cli-research.md) | ✅ complete (5a + 5b-i + 5b-ii-A + 5b-ii-B-1 + 5b-ii-B-2 — identity/install, agent loop, custom instructions/agents, Squad cross-ref, Roo↔CLI mapping, MCP deep-dive, Hooks deep-dive incl. preToolUse/fileRegex verdict, Skills + Scripting/automation, full `@github/copilot-sdk` export catalogue + Path-D embeddability verdict, **CLI Gap Catalog (G-/W- inherited + CG-/CW- new)**) | 2026-04-26 | +| 6 — Gap analysis | [`60-gap-analysis.md`](60-gap-analysis.md) | ✅ complete (unified Chat + CLI gap matrix, 12 grouped sections, ~70 rows, severity tally, top-10 callout, Squad-as-overlay interpretation, Phase 7/8 handoff) | 2026-04-26 | +| 7 — Migration paths | [`70-migration-paths.md`](70-migration-paths.md) | ✅ complete (8 weighted criteria, A/B/C/D + Hybrid scored, side-by-side table, recommendation = **Path Hybrid**, decision tree, sensitivity analysis, Phase-8 hand-off) | 2026-04-26 | +| 8 — Migration playbook | [`80-migration-playbook.md`](80-migration-playbook.md) | ✅ complete (8a + 8b-i + **8b-ii**: shared assets + Chat side + 17-mode table + CLI-side config + preToolUse hook + MCP generator + setup automation + 24-row validation matrix + rollback plan + Path B appendix) | 2026-04-26 | +| 9 — Executive summary | [`00-executive-summary.md`](00-executive-summary.md) | ✅ complete | 2026-04-26 | + +Legend: ⬜ not-started · 🟡 in-progress / partially-seeded · ✅ complete · ⛔ blocked diff --git a/gh_output1.txt b/gh_output1.txt new file mode 100644 index 00000000000..e69de29bb2d From 8e8ff0b71790a2f0356911d8b060a31b0297861e Mon Sep 17 00:00:00 2001 From: Bertan Ari Date: Wed, 29 Apr 2026 10:21:04 -0700 Subject: [PATCH 2/3] docs: note that simurg79/Roo-Code is a personal fork --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 498a847aeb7..c915556babc 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,10 @@ > Your AI-Powered Dev Team, Right in Your Editor +> **Fork notice:** This is a personal fork of [RooCodeInc/Roo-Code](https://github.com/RooCodeInc/Roo-Code) +> maintained at [simurg79/Roo-Code](https://github.com/simurg79/Roo-Code). It tracks upstream and may +> include experimental branches (e.g. `feature/per-mode-allowed-tools-mcp`) that are not yet upstreamed. + ## What's New in v3.53.0 > ### The Roo Code plugin is not going away. From 0bcc609f21e291ff51eb589ea6a142b81830c919 Mon Sep 17 00:00:00 2001 From: Bertan Ari Date: Wed, 29 Apr 2026 12:10:48 -0700 Subject: [PATCH 3/3] chore: extend .gitignore for vault symlink artifacts --- .gitignore | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 8381c043c62..0fbea040b3a 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,8 @@ qdrant_storage/ plans/ roo-cli-*.tar.gz* -.roo +.roo* .roomodes .clinerules +myplans +myscripts