Skip to content

Commit 98c0a02

Browse files
fix: differentiate VS Code and Copilot CLI as separate targets in user-scope registry
Co-authored-by: sergio-sisternes-epam <207026618+sergio-sisternes-epam@users.noreply.github.com> Agent-Logs-Url: https://github.com/microsoft/apm/sessions/b36f06ca-13e4-472b-a4ec-95e22f01f52e
1 parent 1725400 commit 98c0a02

File tree

5 files changed

+51
-26
lines changed

5 files changed

+51
-26
lines changed

docs/src/content/docs/guides/scoped-installation.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ Not all AI tools read primitives from user-level directories. APM warns during `
4040
| Target | User-level directory | Status | Primitives at user scope | Reference |
4141
|--------|---------------------|--------|--------------------------|-----------|
4242
| Claude Code | `~/.claude/` | Supported | commands, agents, skills, hooks | [Claude Code settings](https://docs.anthropic.com/en/docs/claude-code/settings) |
43-
| Copilot | `~/.github/` | Not supported | None (VS Code reads `.github/` from workspace only; user config is via VS Code settings) | [VS Code custom instructions](https://code.visualstudio.com/docs/copilot/customization/custom-instructions) |
43+
| Copilot (CLI) | `~/.copilot/` | Supported | agents | [Custom agents for CLI](https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/create-custom-agents-for-cli) |
44+
| VS Code | User settings.json | Partial | MCP servers only (via VS Code user settings) | [VS Code settings](https://code.visualstudio.com/docs/configure/settings) |
4445
| Cursor | `~/.cursor/` | Not supported | None (user rules are managed via Cursor Settings UI) | [Cursor rules docs](https://cursor.com/docs/rules) |
4546
| OpenCode | `~/.opencode/` | Unverified | None confirmed | No official docs available |
4647

@@ -58,5 +59,6 @@ apm uninstall -g microsoft/apm-sample-package
5859
|----------|-------|
5960
| Team-shared instructions and prompts | Project (`apm install`) |
6061
| Personal Claude Code commands and agents | User (`apm install -g`) |
62+
| Personal Copilot CLI agents | User (`apm install -g`) |
6163
| CI/CD reproducible setup | Project |
62-
| Cross-project coding standards (Claude Code) | User |
64+
| Cross-project coding standards (Claude Code, Copilot CLI) | User |

src/apm_cli/core/scope.py

Lines changed: 28 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,12 @@
1212
- **Claude Code** (fully supported): reads ``~/.claude/`` for global
1313
commands, agents, skills, and ``CLAUDE.md``.
1414
Ref: https://docs.anthropic.com/en/docs/claude-code/settings
15-
- **Copilot** (not supported): VS Code reads ``.github/`` only from the
16-
workspace root; user-level configuration lives in VS Code settings.
17-
Ref: https://code.visualstudio.com/docs/copilot/customization/custom-instructions
15+
- **Copilot CLI** (supported): reads ``~/.copilot/agents/`` for
16+
user-level custom agents.
17+
Ref: https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/create-custom-agents-for-cli
18+
- **VS Code** (partial): supports user-level MCP servers via
19+
VS Code user ``settings.json``; ``.github/`` is workspace-only.
20+
Ref: https://code.visualstudio.com/docs/configure/settings
1821
- **Cursor** (not supported): user-level rules are managed via the
1922
Cursor Settings UI, not the filesystem.
2023
Ref: https://cursor.com/docs/rules
@@ -123,10 +126,14 @@ def ensure_user_dirs() -> Path:
123126
# from it and merges them with project-level ``.claude/``.
124127
# Ref: https://docs.anthropic.com/en/docs/claude-code/settings
125128
#
126-
# * Copilot -- VS Code reads ``.github/`` only from the current
127-
# workspace root. User-level instructions are configured via
128-
# VS Code settings (``settings.json``), not a home-directory file.
129-
# Ref: https://code.visualstudio.com/docs/copilot/customization/custom-instructions
129+
# * Copilot CLI -- ``~/.copilot/agents/`` is the documented user-level
130+
# directory for custom agents. Agents placed here are available
131+
# across all repositories.
132+
# Ref: https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/create-custom-agents-for-cli
133+
#
134+
# * VS Code -- supports user-level MCP server configuration through
135+
# VS Code user settings.json. ``.github/`` is workspace-scoped only.
136+
# Ref: https://code.visualstudio.com/docs/configure/settings
130137
#
131138
# * Cursor -- user-level rules are configured via the Cursor Settings
132139
# UI (Settings > Rules for AI). The ``.cursor/rules/`` directory is
@@ -145,12 +152,19 @@ def ensure_user_dirs() -> Path:
145152
"description": "User-level Claude commands, agents, and settings",
146153
"reference": "https://docs.anthropic.com/en/docs/claude-code/settings",
147154
},
148-
"copilot": {
149-
"supported": False,
150-
"user_root": "~/.github",
151-
"primitives": [],
152-
"description": "Not supported -- VS Code reads .github/ from workspace only",
153-
"reference": "https://code.visualstudio.com/docs/copilot/customization/custom-instructions",
155+
"copilot_cli": {
156+
"supported": True,
157+
"user_root": "~/.copilot",
158+
"primitives": ["agents"],
159+
"description": "User-level custom agents for Copilot CLI",
160+
"reference": "https://docs.github.com/en/copilot/how-tos/copilot-cli/customize-copilot/create-custom-agents-for-cli",
161+
},
162+
"vscode": {
163+
"supported": True,
164+
"user_root": "~/settings.json",
165+
"primitives": ["mcp_servers"],
166+
"description": "MCP servers only (via VS Code user settings.json)",
167+
"reference": "https://code.visualstudio.com/docs/configure/settings",
154168
},
155169
"cursor": {
156170
"supported": False,
@@ -187,6 +201,6 @@ def warn_unsupported_user_scope() -> str:
187201
return ""
188202
names = ", ".join(unsupported)
189203
return (
190-
f"[!] User-scope primitives are only read by Claude Code. "
204+
f"[!] Some targets do not support user-scope primitives. "
191205
f"Targets without native user-level support: {names}"
192206
)

tests/integration/test_global_scope_e2e.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -161,8 +161,8 @@ def test_warns_about_unsupported_targets(self, apm_command, fake_home):
161161
"""Install --global should warn about targets that lack user-scope support."""
162162
result = _run_apm(apm_command, ["install", "--global"], fake_home, fake_home)
163163
combined = result.stdout + result.stderr
164-
assert "copilot" in combined.lower(), (
165-
f"Missing copilot warning in output: {combined}"
164+
assert "cursor" in combined.lower(), (
165+
f"Missing cursor warning in output: {combined}"
166166
)
167167

168168
def test_uninstall_global_shows_scope_info(self, apm_command, fake_home):

tests/unit/core/test_scope.py

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ class TestUserScopeTargets:
158158
"""Validate the target support registry."""
159159

160160
def test_all_known_targets_present(self):
161-
expected = {"copilot", "claude", "cursor", "opencode"}
161+
expected = {"copilot_cli", "vscode", "claude", "cursor", "opencode"}
162162
assert set(USER_SCOPE_TARGETS.keys()) == expected
163163

164164
def test_each_target_has_required_keys(self):
@@ -178,8 +178,17 @@ def test_user_roots_start_with_tilde(self):
178178
def test_claude_is_supported(self):
179179
assert USER_SCOPE_TARGETS["claude"]["supported"] is True
180180

181-
def test_copilot_is_not_supported(self):
182-
assert USER_SCOPE_TARGETS["copilot"]["supported"] is False
181+
def test_copilot_cli_is_supported(self):
182+
assert USER_SCOPE_TARGETS["copilot_cli"]["supported"] is True
183+
184+
def test_copilot_cli_supports_agents(self):
185+
assert "agents" in USER_SCOPE_TARGETS["copilot_cli"]["primitives"]
186+
187+
def test_vscode_is_supported(self):
188+
assert USER_SCOPE_TARGETS["vscode"]["supported"] is True
189+
190+
def test_vscode_supports_mcp_servers(self):
191+
assert "mcp_servers" in USER_SCOPE_TARGETS["vscode"]["primitives"]
183192

184193
def test_cursor_is_not_supported(self):
185194
assert USER_SCOPE_TARGETS["cursor"]["supported"] is False
@@ -208,14 +217,14 @@ class TestScopeWarnings:
208217

209218
def test_get_unsupported_targets(self):
210219
unsupported = get_unsupported_targets()
211-
assert "copilot" in unsupported
212220
assert "cursor" in unsupported
213221
assert "opencode" in unsupported
214222
assert "claude" not in unsupported
223+
assert "copilot_cli" not in unsupported
224+
assert "vscode" not in unsupported
215225

216226
def test_warn_message_includes_unsupported_names(self):
217227
msg = warn_unsupported_user_scope()
218228
assert msg # non-empty
219-
assert "copilot" in msg
220229
assert "cursor" in msg
221-
assert "Claude Code" in msg
230+
assert "opencode" in msg

tests/unit/test_install_command.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -638,7 +638,7 @@ def test_global_flag_shows_scope_info(self):
638638
assert result.exit_code == 1
639639
assert "user scope" in result.output.lower() or "~/.apm/" in result.output
640640
# Should warn about unsupported targets
641-
assert "copilot" in result.output.lower()
641+
assert "cursor" in result.output.lower()
642642
finally:
643643
os.chdir(self.original_dir)
644644

@@ -656,7 +656,7 @@ def test_global_short_flag_g(self):
656656
assert (fake_home / ".apm" / "apm_modules").is_dir()
657657
assert "user scope" in result.output.lower() or "~/.apm/" in result.output
658658
# Should warn about unsupported targets
659-
assert "copilot" in result.output.lower()
659+
assert "cursor" in result.output.lower()
660660
finally:
661661
os.chdir(self.original_dir)
662662

0 commit comments

Comments
 (0)