Skip to content

fix: gate .claude/commands/ deployment behind integrate_claude flag#443

Merged
danielmeppiel merged 5 commits into
microsoft:mainfrom
neop26:fix/command-integrator-respects-target-flag
Mar 26, 2026
Merged

fix: gate .claude/commands/ deployment behind integrate_claude flag#443
danielmeppiel merged 5 commits into
microsoft:mainfrom
neop26:fix/command-integrator-respects-target-flag

Conversation

@neop26
Copy link
Copy Markdown
Contributor

@neop26 neop26 commented Mar 24, 2026

The CommandIntegrator was called unconditionally in _integrate_package_primitives(), ignoring the integrate_claude flag derived from the detected or configured target.

This caused .claude/commands/ to be created on every apm install, even when the project is configured with target: copilot (vscode), which sets integrate_claude=False.

The docstring of should_integrate_claude() explicitly states that 'commands' should be governed by this flag, matching the pattern already applied to Claude agents and hooks. The OpenCode commands integrator has a similar self-guard (.opencode/ must exist).

Fix: wrap integrate_package_commands() in if integrate_claude: so it is consistent with all other Claude-specific integration paths.

Reproducer: set target: copilot in apm.yml, add .prompt.md files under .apm/prompts/, run apm install — .claude/commands/ is created despite no Claude target being configured.

Description

Brief description of changes and motivation.

Fixes # (issue)

Type of change

  • Bug fix
  • New feature
  • Documentation
  • Maintenance / refactor

Testing

  • Tested locally
  • All existing tests pass
  • Added tests for new functionality (if applicable)

The CommandIntegrator was called unconditionally in
_integrate_package_primitives(), ignoring the integrate_claude flag
derived from the detected or configured target.

This caused .claude/commands/ to be created on every apm install,
even when the project is configured with target: copilot (vscode),
which sets integrate_claude=False.

The docstring of should_integrate_claude() explicitly states that
'commands' should be governed by this flag, matching the pattern
already applied to Claude agents and hooks. The OpenCode commands
integrator has a similar self-guard (.opencode/ must exist).

Fix: wrap integrate_package_commands() in if integrate_claude: so it
is consistent with all other Claude-specific integration paths.

Reproducer: set target: copilot in apm.yml, add .prompt.md files
under .apm/prompts/, run apm install — .claude/commands/ is created
despite no Claude target being configured.
@neop26 neop26 requested a review from danielmeppiel as a code owner March 24, 2026 18:43
Copilot AI review requested due to automatic review settings March 24, 2026 18:43
@neop26
Copy link
Copy Markdown
Contributor Author

neop26 commented Mar 24, 2026

@microsoft-github-policy-service agree

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes an install-time integration bug where Claude command deployment (.claude/commands/) ran unconditionally during apm install, ignoring the integrate_claude flag derived from the detected/configured target (e.g., target: copilot / vscode).

Changes:

  • Gate .claude/commands/ deployment by wrapping integrate_package_commands() in if integrate_claude:.
  • Align Claude command integration behavior with other Claude-specific integrations (agents/hooks) that already respect integrate_claude.

Comment on lines +962 to +964
_log_integration(f" └─ {command_result.files_integrated} commands integrated -> .claude/commands/")
if command_result.files_updated > 0:
_log_integration(f" └─ {command_result.files_updated} commands updated")
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These log strings include Unicode box-drawing characters ("└" and "─"), which violates the repo's ASCII-only encoding rule for source/CLI output (see .github/instructions/encoding.instructions.md). Please switch this message prefix to plain ASCII (for example, a simple "-" or the bracket status symbols) so Windows cp1252 terminals do not crash with UnicodeEncodeError.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These log strings match the existing pattern used throughout _integrate_package_primitives() — all ~15 existing _log_integration calls on lines 849, 864, 879, etc. use the same └─ character. Changing only the new lines would create an inconsistency. If there's a repo-wide ASCII encoding requirement, I'm happy to raise a separate PR to update all occurrences consistently.

Comment on lines +954 to +958
if integrate_claude:
command_result = command_integrator.integrate_package_commands(
package_info, project_root,
force=force, managed_files=managed_files,
diagnostics=diagnostics,
Copy link

Copilot AI Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add/adjust a unit test to cover this regression: when the detected/configured target yields integrate_claude=False (e.g., target=vscode/copilot), apm install should not call integrate_package_commands and should not create/deploy anything under .claude/commands/. This will prevent future accidental reintroduction of unconditional Claude command integration.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor Author

@neop26 neop26 Mar 24, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done — added TestIntegratePackagePrimitivesTargetGating in test_command_integrator.py with two tests: one verifying integrate_package_commands is not called when integrate_claude=False (target=copilot/vscode), and one verifying it is called when integrate_claude=True.

neop26 and others added 3 commits March 25, 2026 08:27
…mands/

Covers the fix in _integrate_package_primitives():
- When integrate_claude=False (target=copilot/vscode), integrate_package_commands
  must not be called and .claude/commands/ must not be created.
- When integrate_claude=True (target=claude/all), integrate_package_commands
  must be called.
Copy link
Copy Markdown
Collaborator

@danielmeppiel danielmeppiel left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Architectural Review

Direction: Correct. The fix is needed and well-scoped.

I audited all 13 integrator calls in _integrate_package_primitives(). This is the only remaining unguarded call -- every other non-universal integrator is protected by either an external if integrate_* gate or an internal self-guard (e.g., OpenCode commands checks .opencode/ exists at L197-202). The .claude/commands/ block at L974 has neither, so it creates .claude/ from nothing via mkdir(parents=True) when integrate_vscode=True but integrate_claude=False.

Our recent presence-only target detection changes (merged in a1ae126) do NOT prevent this -- the early return at L846 only fires when ALL flags are False, which doesn't apply here.

Required

  1. Rebase onto current main. install.py has had 4+ significant commits since this PR was opened (target registry refactor, presence-only detection, review fixes). The PR will not merge cleanly as-is.

Suggested (not blocking)

  1. Add a self-guard inside integrate_package_commands() for defense-in-depth, matching the pattern in integrate_package_commands_opencode():
# At the top of integrate_package_commands():
claude_dir = project_root / ".claude"
if not claude_dir.is_dir():
    return IntegrationResult(
        files_integrated=0, files_updated=0,
        files_skipped=0, target_paths=[], links_resolved=0,
    )
  1. Consider using tmp_path in new tests (optional -- current file uses tempfile.mkdtemp() consistently, so either convention is fine).

Tests look good. Regression risk is very low -- existing Claude users are unaffected since integrate_claude=True when .claude/ exists.

@danielmeppiel danielmeppiel merged commit fdd0003 into microsoft:main Mar 26, 2026
6 checks passed
sergio-sisternes-epam pushed a commit that referenced this pull request May 19, 2026
…443)

* fix: gate .claude/commands/ deployment behind integrate_claude flag

The CommandIntegrator was called unconditionally in
_integrate_package_primitives(), ignoring the integrate_claude flag
derived from the detected or configured target.

This caused .claude/commands/ to be created on every apm install,
even when the project is configured with target: copilot (vscode),
which sets integrate_claude=False.

The docstring of should_integrate_claude() explicitly states that
'commands' should be governed by this flag, matching the pattern
already applied to Claude agents and hooks. The OpenCode commands
integrator has a similar self-guard (.opencode/ must exist).

Fix: wrap integrate_package_commands() in if integrate_claude: so it
is consistent with all other Claude-specific integration paths.

Reproducer: set target: copilot in apm.yml, add .prompt.md files
under .apm/prompts/, run apm install — .claude/commands/ is created
despite no Claude target being configured.

* test: add regression tests for integrate_claude gating of .claude/commands/

Covers the fix in _integrate_package_primitives():
- When integrate_claude=False (target=copilot/vscode), integrate_package_commands
  must not be called and .claude/commands/ must not be created.
- When integrate_claude=True (target=claude/all), integrate_package_commands
  must be called.

* test: fix regression test import

---------

Co-authored-by: Daniel Meppiel <51440732+danielmeppiel@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants